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.

1298 lines
38 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. trustdom.c
  5. Abstract:
  6. Implementation of the functions to manage the trust link between 2 servers
  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 <db.h>
  18. #include <lsads.h>
  19. #include <lsasrvmm.h>
  20. #include <lsaisrv.h>
  21. #include <lmcons.h>
  22. #include <cryptdll.h>
  23. #include <winbase.h> // For RtlSecureZeroMemory
  24. #include "trustdom.h"
  25. DWORD
  26. DsRolepSetLsaDnsInformationNoParent(
  27. IN LPWSTR DnsDomainName
  28. )
  29. /*++
  30. Routine Description:
  31. In the case where we are installing as a standalong or root Dc, set the Lsa
  32. POLICY_DNS_DOMAIN_INFORMATION DnsForestName value to point to ourselves.
  33. Arguments:
  34. DnsDomainName - Dns domain path to set
  35. Returns:
  36. ERROR_SUCCESS - Success
  37. --*/
  38. {
  39. NTSTATUS Status = STATUS_SUCCESS;
  40. PPOLICY_DNS_DOMAIN_INFO CurrentDnsInfo;
  41. PLSAPR_POLICY_INFORMATION LsaPolicy;
  42. OBJECT_ATTRIBUTES ObjectAttributes;
  43. HANDLE Policy;
  44. //
  45. // Open our local policy
  46. //
  47. RtlZeroMemory( &ObjectAttributes, sizeof( ObjectAttributes ) );
  48. Status = LsaOpenPolicy( NULL,
  49. &ObjectAttributes,
  50. POLICY_WRITE,
  51. &Policy );
  52. if ( NT_SUCCESS( Status ) ) {
  53. //
  54. // Get the current information
  55. //
  56. Status = LsaQueryInformationPolicy( Policy,
  57. PolicyDnsDomainInformation,
  58. ( PVOID * )&LsaPolicy );
  59. if ( NT_SUCCESS( Status ) ) {
  60. //
  61. // Add in the new...
  62. //
  63. CurrentDnsInfo = (PPOLICY_DNS_DOMAIN_INFO)LsaPolicy;
  64. RtlInitUnicodeString( &CurrentDnsInfo->DnsForestName, DnsDomainName );
  65. DsRolepLogPrint(( DEB_TRACE, "Configuring DnsForestName to %ws\n",
  66. DnsDomainName ));
  67. //
  68. // And write it out..
  69. //
  70. Status = LsaSetInformationPolicy( Policy,
  71. PolicyDnsDomainInformation,
  72. LsaPolicy );
  73. //
  74. // Don't want to actually free the passed in buffer
  75. //
  76. RtlZeroMemory( &CurrentDnsInfo->DnsForestName, sizeof( UNICODE_STRING ) );
  77. LsaIFree_LSAPR_POLICY_INFORMATION( PolicyDnsDomainInformation, LsaPolicy );
  78. }
  79. LsaClose( Policy );
  80. }
  81. DsRolepLogOnFailure( Status,
  82. DsRolepLogPrint(( DEB_TRACE,
  83. "DsRolepSetLsaDnsInformationNoParent failed with 0x%lx\n",
  84. Status )) );
  85. return( RtlNtStatusToDosError( Status ) );
  86. }
  87. DWORD
  88. DsRolepCreateTrustedDomainObjects(
  89. IN HANDLE CallerToken,
  90. IN LPWSTR ParentDc,
  91. IN LPWSTR DnsDomainName,
  92. IN PPOLICY_DNS_DOMAIN_INFO ParentDnsDomainInfo,
  93. IN ULONG Options
  94. )
  95. /*++
  96. Routine Description:
  97. Creates the trusted domain object on the domains if they should exist and sets the
  98. Lsa POLICY_DNS_DOMAIN_INFORMATION DnsTree value to either the value of our parent in
  99. a parent/child install, or as the root otherwise.
  100. Arguments:
  101. ParentDc - Optional. Name of the parent Dc
  102. DnsDomainName - Dns name of the domain we're installing into
  103. ParentDnsDomainInfo - DNS domain information obtained from the parent
  104. Options - Options that dictate what steps are taken
  105. Returns:
  106. ERROR_SUCCESS - Success
  107. ERROR_INVALID_PARAMETER - A bad results pointer was given
  108. --*/
  109. {
  110. DWORD Win32Err = ERROR_SUCCESS;
  111. NTSTATUS Status = STATUS_SUCCESS;
  112. UNICODE_STRING ParentServer;
  113. HANDLE LocalPolicy = NULL , ParentPolicy = NULL;
  114. PPOLICY_DNS_DOMAIN_INFO LocalDnsInfo = NULL;
  115. OBJECT_ATTRIBUTES ObjectAttributes;
  116. LSA_HANDLE ParentTrustedDomain = NULL;
  117. WCHAR GeneratedPassword[ PWLEN + 1 ];
  118. ULONG Length = PWLEN;
  119. LSA_AUTH_INFORMATION AuthData;
  120. TRUSTED_DOMAIN_AUTH_INFORMATION AuthInfoEx;
  121. DSROLEP_CURRENT_OP1( DSROLEEVT_SET_LSA_FROM, ParentDc );
  122. //
  123. // Make the Lsa think that we're initialized
  124. //
  125. Status = LsapDsInitializeDsStateInfo( LsapDsDsSetup );
  126. if ( !NT_SUCCESS( Status ) ) {
  127. DsRolepLogPrint(( DEB_TRACE,
  128. "Failed to convince Lsa to reinitialize: 0x%lx\n",
  129. Status ));
  130. return( RtlNtStatusToDosError( Status ) );
  131. }
  132. //
  133. // Prepare the Auth Info
  134. //
  135. RtlZeroMemory( &AuthInfoEx, sizeof(AuthInfoEx) );
  136. RtlZeroMemory( &AuthData, sizeof(AuthData) );
  137. RtlZeroMemory( &GeneratedPassword, sizeof(GeneratedPassword) );
  138. Win32Err = DsRolepGenerateRandomPassword( Length,
  139. GeneratedPassword );
  140. if ( ERROR_SUCCESS == Win32Err ) {
  141. Status = NtQuerySystemTime( &AuthData.LastUpdateTime );
  142. if ( NT_SUCCESS( Status ) ) {
  143. AuthData.AuthType = TRUST_AUTH_TYPE_CLEAR;
  144. AuthData.AuthInfoLength = Length;
  145. AuthData.AuthInfo = (PUCHAR)GeneratedPassword;
  146. AuthInfoEx.IncomingAuthInfos = 1;
  147. AuthInfoEx.IncomingAuthenticationInformation = &AuthData;
  148. AuthInfoEx.IncomingPreviousAuthenticationInformation = NULL;
  149. AuthInfoEx.OutgoingAuthInfos = 1;
  150. AuthInfoEx.OutgoingAuthenticationInformation = &AuthData;
  151. AuthInfoEx.OutgoingPreviousAuthenticationInformation = NULL;
  152. }
  153. } else {
  154. DsRolepLogPrint(( DEB_ERROR,
  155. "Failed to generate a trust password: %lu\n",
  156. Win32Err ));
  157. Status = STATUS_UNSUCCESSFUL;
  158. }
  159. if ( NT_SUCCESS( Status ) ) {
  160. //
  161. // Open both lsas
  162. //
  163. RtlInitUnicodeString( &ParentServer, ParentDc );
  164. RtlZeroMemory( &ObjectAttributes, sizeof( ObjectAttributes ) );
  165. Status = ImpLsaOpenPolicy( CallerToken,
  166. &ParentServer,
  167. &ObjectAttributes,
  168. POLICY_TRUST_ADMIN | POLICY_VIEW_LOCAL_INFORMATION,
  169. &ParentPolicy
  170. );
  171. if ( NT_SUCCESS( Status ) ) {
  172. RtlZeroMemory( &ObjectAttributes, sizeof( ObjectAttributes ) );
  173. Status = LsaOpenPolicy( NULL,
  174. &ObjectAttributes,
  175. POLICY_TRUST_ADMIN | POLICY_VIEW_LOCAL_INFORMATION,
  176. &LocalPolicy );
  177. } else {
  178. DsRolepLogPrint(( DEB_TRACE,
  179. "OpenPolicy on %ws failed with 0x%lx\n",
  180. ParentDc,
  181. Status ));
  182. }
  183. }
  184. //
  185. // Get our local dns domain information
  186. //
  187. if ( NT_SUCCESS( Status ) ) {
  188. Status = LsaQueryInformationPolicy( LocalPolicy,
  189. PolicyDnsDomainInformation,
  190. &LocalDnsInfo );
  191. }
  192. //
  193. // Now, create the trusted domain objects
  194. //
  195. if ( NT_SUCCESS( Status ) ) {
  196. DSROLEP_CURRENT_OP1( DSROLEEVT_CREATE_PARENT_TRUST,
  197. ParentDnsDomainInfo->DnsDomainName.Buffer );
  198. if ( !FLAG_ON( Options, DSROLE_DC_PARENT_TRUST_EXISTS ) ||
  199. FLAG_ON( Options, DSROLE_DC_CREATE_TRUST_AS_REQUIRED ) ) {
  200. DsRoleDebugOut(( DEB_TRACE_DS, "Creating trust object ( %lu ) on %ws\n",
  201. Options,
  202. ParentDc ));
  203. Status = DsRolepCreateParentTrustObject( CallerToken,
  204. ParentPolicy,
  205. LocalDnsInfo,
  206. Options,
  207. &AuthInfoEx,
  208. &ParentTrustedDomain );
  209. if ( Status == STATUS_OBJECT_NAME_COLLISION ) {
  210. DSROLEP_FAIL2( RtlNtStatusToDosError( Status ),
  211. DSROLERES_PARENT_TRUST_EXISTS, ParentDc, DnsDomainName );
  212. } else {
  213. DSROLEP_FAIL2( RtlNtStatusToDosError( Status ),
  214. DSROLERES_PARENT_TRUST_FAIL, DnsDomainName, ParentDc );
  215. }
  216. }
  217. //
  218. // Now the child
  219. //
  220. if ( NT_SUCCESS( Status ) ) {
  221. DSROLEP_CURRENT_OP1( DSROLEEVT_CREATE_TRUST,
  222. LocalDnsInfo->DnsDomainName.Buffer );
  223. Status = DsRolepCreateChildTrustObject( CallerToken,
  224. ParentPolicy,
  225. LocalPolicy,
  226. ParentDnsDomainInfo,
  227. LocalDnsInfo,
  228. &AuthInfoEx,
  229. Options );
  230. if ( !NT_SUCCESS( Status ) ) {
  231. DsRolepLogPrint(( DEB_TRACE,
  232. "DsRolepCreateChildTrustObject failed: 0x%lx\n",
  233. Status ));
  234. }
  235. //
  236. // If we created the parent object, we had better try and delete it now. Note that
  237. // it isn't fatal if we can't
  238. //
  239. if ( !NT_SUCCESS( Status ) && !FLAG_ON( Options, DSROLE_DC_PARENT_TRUST_EXISTS ) ) {
  240. NTSTATUS Status2;
  241. Status2 = ImpLsaDelete( CallerToken, ParentTrustedDomain );
  242. if ( !NT_SUCCESS( Status2 ) ) {
  243. DsRolepLogPrint(( DEB_TRACE,
  244. "LsaDelete of ParentTrustedDomain failed: 0x%lx\n",
  245. Status2 ));
  246. }
  247. } else {
  248. if ( ParentTrustedDomain ) {
  249. ImpLsaClose( CallerToken, ParentTrustedDomain );
  250. }
  251. }
  252. }
  253. }
  254. LsaFreeMemory( LocalDnsInfo );
  255. if ( LocalPolicy ) {
  256. LsaClose( LocalPolicy );
  257. }
  258. if ( ParentPolicy ) {
  259. ImpLsaClose( CallerToken, ParentPolicy );
  260. }
  261. // Don't leave the information in the pagefile
  262. RtlSecureZeroMemory( &AuthInfoEx, sizeof(AuthInfoEx) );
  263. RtlSecureZeroMemory( &AuthData, sizeof(AuthData) );
  264. RtlSecureZeroMemory( &GeneratedPassword, sizeof(GeneratedPassword) );
  265. //
  266. // We won't bother cleaning up any of the DnsTreeInformation we set on the local machine in
  267. // the failure case, since it won't hurt anything to have it here.
  268. //
  269. return( RtlNtStatusToDosError( Status ) );
  270. }
  271. NTSTATUS
  272. DsRolepHandlePreExistingTrustObject(
  273. IN HANDLE Token, OPTIONAL
  274. IN LSA_HANDLE Lsa,
  275. TRUSTED_DOMAIN_INFORMATION_EX *pTDIEx,
  276. TRUSTED_DOMAIN_AUTH_INFORMATION * pAuthInfoEx,
  277. IN BOOLEAN ReuseQuarantineBit,
  278. OUT PLSA_HANDLE TrustedDomainHandle
  279. )
  280. /*++
  281. This routine does the appropriate handling for the case of the pre existing
  282. trust object ( ie opening the object, checking if it were the right one
  283. and then deleting it if required
  284. Paramters
  285. Token -- token to impersonate if necessary (used when talking to remote
  286. server)
  287. Lsa Handle to the LSA
  288. pTDIEx the TDO that is being created that recieved the object name collision error
  289. ReuseQuarantineBit - If quarantine bit is set on the existing object, do we
  290. keep it or erase it?
  291. Return Values
  292. STATUS_SUCCESS
  293. Other Error Codes
  294. --*/
  295. {
  296. NTSTATUS Status = STATUS_SUCCESS;
  297. LSA_HANDLE TrustedDomain = 0;
  298. ULONG DesiredAccess = DELETE;
  299. *TrustedDomainHandle = 0;
  300. // We should have something to go on
  301. ASSERT( pTDIEx->Sid
  302. || (pTDIEx->FlatName.Length > 0)
  303. || (pTDIEx->Name.Length > 0) );
  304. if( ReuseQuarantineBit ) {
  305. DesiredAccess |= TRUSTED_QUERY_DOMAIN_NAME;
  306. }
  307. //
  308. // We have a conflict, either by name or by sid.
  309. // Try to open by sid, dns domain name, and then flat domain name
  310. //
  311. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  312. if ( (Status == STATUS_OBJECT_NAME_NOT_FOUND)
  313. && pTDIEx->Sid ) {
  314. if ( ARGUMENT_PRESENT(Token) ) {
  315. Status = ImpLsaOpenTrustedDomain( Token,
  316. Lsa,
  317. pTDIEx->Sid,
  318. DesiredAccess,
  319. ( PVOID * )&TrustedDomain);
  320. } else {
  321. Status = LsaOpenTrustedDomain( Lsa,
  322. pTDIEx->Sid,
  323. DesiredAccess,
  324. ( PVOID * )&TrustedDomain);
  325. }
  326. if ( !NT_SUCCESS( Status ) ) {
  327. DsRolepLogPrint(( DEB_WARN,
  328. "Failed to find trust object by sid: 0x%lx\n",
  329. Status ));
  330. if ( STATUS_NO_SUCH_DOMAIN == Status ) {
  331. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  332. }
  333. }
  334. }
  335. if ( (Status == STATUS_OBJECT_NAME_NOT_FOUND)
  336. && pTDIEx->Name.Length > 0 ) {
  337. //
  338. // Couldn't find by sid -- try dns name
  339. //
  340. if ( ARGUMENT_PRESENT(Token) ) {
  341. Status = ImpLsaOpenTrustedDomainByName( Token,
  342. Lsa,
  343. &pTDIEx->Name,
  344. DesiredAccess,
  345. ( PVOID * ) &TrustedDomain );
  346. } else {
  347. Status = LsaOpenTrustedDomainByName( Lsa,
  348. &pTDIEx->Name,
  349. DesiredAccess,
  350. ( PVOID * ) &TrustedDomain );
  351. }
  352. if ( !NT_SUCCESS( Status ) ) {
  353. WCHAR *BufpTDIEx = NULL;
  354. DsRolepUnicodestringtowstr( BufpTDIEx, pTDIEx->Name )
  355. if (BufpTDIEx) {
  356. DsRolepLogPrint(( DEB_WARN,
  357. "Failed to find trust object for %ws: 0x%lx\n",
  358. BufpTDIEx,
  359. Status ));
  360. free(BufpTDIEx);
  361. }
  362. }
  363. }
  364. if ( (Status == STATUS_OBJECT_NAME_NOT_FOUND)
  365. && pTDIEx->FlatName.Length > 0 ) {
  366. //
  367. // Couldn't find by dns name -- try flat name
  368. //
  369. if ( ARGUMENT_PRESENT(Token) ) {
  370. Status = ImpLsaOpenTrustedDomainByName( Token,
  371. Lsa,
  372. &pTDIEx->FlatName,
  373. DesiredAccess,
  374. ( PVOID * )&TrustedDomain );
  375. } else {
  376. Status = LsaOpenTrustedDomainByName( Lsa,
  377. &pTDIEx->FlatName,
  378. DesiredAccess,
  379. ( PVOID * )&TrustedDomain );
  380. }
  381. if ( !NT_SUCCESS( Status ) ) {
  382. WCHAR *BufpTDIEx = NULL;
  383. DsRolepUnicodestringtowstr( BufpTDIEx, pTDIEx->FlatName )
  384. if (BufpTDIEx) {
  385. DsRolepLogPrint(( DEB_WARN,
  386. "Failed to find trust object for %ws: 0x%lx\n",
  387. BufpTDIEx,
  388. Status ));
  389. free(BufpTDIEx);
  390. }
  391. }
  392. }
  393. //
  394. // If reusing the quarantine bit is asked, query the TDO to see
  395. // if the domain is quarantined.
  396. //
  397. if( NT_SUCCESS( Status ) && ReuseQuarantineBit ) {
  398. PTRUSTED_DOMAIN_INFORMATION_EX Buffer;
  399. if( ARGUMENT_PRESENT( Token ) ) {
  400. Status = ImpLsaQueryInfoTrustedDomain( Token,
  401. TrustedDomain,
  402. TrustedDomainInformationEx,
  403. &Buffer );
  404. } else {
  405. Status = LsaQueryInfoTrustedDomain( TrustedDomain,
  406. TrustedDomainInformationEx,
  407. &Buffer );
  408. }
  409. //
  410. // If successfully queried, and the domain is quarantined, then
  411. // modify the new object to quarantine as well.
  412. //
  413. if( NT_SUCCESS( Status ) ) {
  414. if( FLAG_ON( Buffer->TrustAttributes, TRUST_ATTRIBUTE_QUARANTINED_DOMAIN ) ) {
  415. pTDIEx->TrustAttributes |= TRUST_ATTRIBUTE_QUARANTINED_DOMAIN;
  416. }
  417. LsaFreeMemory( Buffer );
  418. }
  419. }
  420. if ( NT_SUCCESS( Status ) ) {
  421. //
  422. // We found it
  423. //
  424. ASSERT( 0 != TrustedDomain );
  425. if ( ARGUMENT_PRESENT(Token) ) {
  426. Status = ImpLsaDelete( Token, TrustedDomain );
  427. } else {
  428. Status = LsaDelete( TrustedDomain );
  429. }
  430. if ( NT_SUCCESS( Status ) ) {
  431. //
  432. // Raise an event that we had deleted an existing trust object
  433. //
  434. SpmpReportEvent( TRUE,
  435. EVENTLOG_WARNING_TYPE,
  436. DSROLERES_INCOMPATIBLE_TRUST,
  437. 0,
  438. sizeof( ULONG ),
  439. &Status,
  440. 1,
  441. pTDIEx->Name.Buffer );
  442. DSROLEP_SET_NON_FATAL_ERROR( 0 );
  443. } else {
  444. DsRolepLogPrint(( DEB_WARN,
  445. "Failed to delete trust object: 0x%lx\n",
  446. Status ));
  447. }
  448. } else {
  449. DsRolepLogPrint(( DEB_WARN,
  450. "Couldn't find existing trust object: 0x%lx\n",
  451. Status ));
  452. }
  453. //
  454. // At this point, we tried our best to remove the offending object
  455. // Retry the create
  456. //
  457. Status = STATUS_SUCCESS;
  458. DsRolepLogPrint(( DEB_TRACE, "Attempting to recreate trust object\n" ));
  459. //
  460. // Now, let us go ahead and recreate the trust object on the
  461. // parent
  462. //
  463. if ( ARGUMENT_PRESENT(Token) ) {
  464. Status = ImpLsaCreateTrustedDomainEx( Token,
  465. Lsa,
  466. pTDIEx,
  467. pAuthInfoEx,
  468. DELETE, // the only thing we do with
  469. // this handle is delete on
  470. // failure
  471. &TrustedDomain );
  472. } else {
  473. Status = LsaCreateTrustedDomainEx( Lsa,
  474. pTDIEx,
  475. pAuthInfoEx,
  476. DELETE, // the only thing we do with
  477. // this handle is delete on
  478. // failure
  479. &TrustedDomain );
  480. }
  481. if ( !NT_SUCCESS( Status ) ) {
  482. //
  483. // We want to capture and examine these cases
  484. //
  485. WCHAR *BufpTDIEx = NULL;
  486. ASSERT( NT_SUCCESS( Status ) );
  487. DsRolepUnicodestringtowstr( BufpTDIEx, pTDIEx->Name )
  488. if (BufpTDIEx) {
  489. DsRolepLogPrint(( DEB_TRACE,
  490. "Second Trust creation"
  491. "with %ws failed with 0x%lx\n",
  492. BufpTDIEx,
  493. Status ));
  494. free(BufpTDIEx);
  495. }
  496. }
  497. if (NT_SUCCESS(Status))
  498. {
  499. *TrustedDomainHandle = TrustedDomain;
  500. }
  501. else
  502. {
  503. ASSERT(!TrustedDomain);
  504. }
  505. return (Status);
  506. }
  507. NTSTATUS
  508. DsRolepCreateParentTrustObject(
  509. IN HANDLE CallerToken,
  510. IN LSA_HANDLE ParentLsa,
  511. IN PPOLICY_DNS_DOMAIN_INFO ChildDnsInfo,
  512. IN ULONG Options,
  513. IN PTRUSTED_DOMAIN_AUTH_INFORMATION AuthInfoEx,
  514. OUT PLSA_HANDLE TrustedDomainHandle
  515. )
  516. /*++
  517. Routine Description:
  518. Creates the trusted domain object on the parent domain. If the object does not exist,
  519. it will create the object and initialize it with a random password
  520. Arguments:
  521. CallerToken - token to impersonate when talking to remote server
  522. ParentLsa - Handle to the Lsa on the parent Dc
  523. ChildDnsInfo - POLICY_DNS_DOMAIN_INFORMAITON from ourself
  524. Options - Options that dictate what steps are taken
  525. TrustedDomainHandle - Where the trusted domain handle is returned
  526. Returns:
  527. ERROR_SUCCESS - Success
  528. ERROR_INVALID_PARAMETER - A bad results pointer was given
  529. --*/
  530. {
  531. NTSTATUS Status = STATUS_SUCCESS;
  532. WCHAR GeneratedPassword[ PWLEN + 1 ];
  533. TRUSTED_DOMAIN_INFORMATION_EX TDIEx;
  534. LSA_AUTH_INFORMATION AuthData;
  535. PTRUSTED_DOMAIN_INFORMATION_EX TrustInfoEx = NULL;
  536. LSA_HANDLE TrustedDomain;
  537. LARGE_INTEGER Time;
  538. ULONG Seed, Length = PWLEN, i, Win32Err;
  539. PSID OpenSid = NULL;
  540. BOOLEAN DeleteExistingTrust = FALSE;
  541. RtlCopyMemory( &TDIEx.Name, &ChildDnsInfo->DnsDomainName,
  542. sizeof( UNICODE_STRING ) );
  543. RtlCopyMemory( &TDIEx.FlatName, &ChildDnsInfo->Name,
  544. sizeof( UNICODE_STRING ) );
  545. TDIEx.Sid = ChildDnsInfo->Sid;
  546. if ( TDIEx.Name.Length &&
  547. TDIEx.Name.Buffer[ ( TDIEx.Name.Length - 1 ) / sizeof(WCHAR)] == L'.' ) {
  548. TDIEx.Name.Buffer[ ( TDIEx.Name.Length - 1 ) / sizeof(WCHAR)] = UNICODE_NULL;
  549. TDIEx.Name.Length -= sizeof(WCHAR);
  550. }
  551. TDIEx.TrustDirection = TRUST_DIRECTION_BIDIRECTIONAL;
  552. TDIEx.TrustType = TRUST_TYPE_UPLEVEL;
  553. TDIEx.TrustAttributes = TRUST_ATTRIBUTE_WITHIN_FOREST;
  554. {
  555. WCHAR *BufpTDIEx = NULL;
  556. DsRolepLogPrint(( DEB_TRACE, "Creating trusted domain object on parent\n" ));
  557. DsRolepUnicodestringtowstr( BufpTDIEx, TDIEx.Name );
  558. if (BufpTDIEx) {
  559. DsRolepLogPrint(( DEB_TRACE,
  560. "\tDnsDomain: %ws\n",
  561. BufpTDIEx,
  562. Status ));
  563. free(BufpTDIEx);
  564. }
  565. DsRolepUnicodestringtowstr( BufpTDIEx, TDIEx.FlatName );
  566. if (BufpTDIEx) {
  567. DsRolepLogPrint(( DEB_TRACE,
  568. "\tFlat name: %ws\n",
  569. BufpTDIEx,
  570. Status ));
  571. free(BufpTDIEx);
  572. }
  573. DsRolepLogPrint(( DEB_TRACE, "\tDirection: %lu\n", TDIEx.TrustDirection ));
  574. DsRolepLogPrint(( DEB_TRACE, "\tType: %lu\n", TDIEx.TrustType ));
  575. DsRolepLogPrint(( DEB_TRACE, "\tAttributes: 0x%lx\n", TDIEx.TrustAttributes ));
  576. }
  577. Status = ImpLsaCreateTrustedDomainEx( CallerToken,
  578. ParentLsa,
  579. &TDIEx,
  580. AuthInfoEx,
  581. DELETE, // we may have to delete on
  582. // rollback
  583. &TrustedDomain );
  584. if ( Status == STATUS_OBJECT_NAME_COLLISION ) {
  585. DsRolepLogPrint(( DEB_TRACE, "Parent trust object already exists on parent\n" ));
  586. //
  587. // If this is a downlevel upgrade scenario, then we want to use the quarantine
  588. // bit of the existing TDO, since it is possible to have a child domain quarantined.
  589. //
  590. Status = DsRolepHandlePreExistingTrustObject(
  591. CallerToken,
  592. ParentLsa,
  593. &TDIEx,
  594. AuthInfoEx,
  595. ( BOOLEAN ) FLAG_ON( Options, DSROLE_DC_DOWNLEVEL_UPGRADE ),
  596. &TrustedDomain
  597. );
  598. } else if ( Status != STATUS_SUCCESS ) {
  599. WCHAR *BufpTDIEx = NULL;
  600. DsRolepUnicodestringtowstr( BufpTDIEx, TDIEx.Name );
  601. if (BufpTDIEx) {
  602. DsRolepLogPrint(( DEB_TRACE,
  603. "Parent LsaCreateTrustedDomainEx on %ws failed with 0x%lx\n",
  604. BufpTDIEx,
  605. Status ));
  606. free(BufpTDIEx);
  607. }
  608. }
  609. if ( NT_SUCCESS( Status ) ) {
  610. *TrustedDomainHandle = TrustedDomain;
  611. }
  612. return( Status );
  613. }
  614. #pragma warning(push)
  615. #pragma warning(disable:4701) // Compiler can't tell if TDIEx.TrustDirection is initialized before use
  616. NTSTATUS
  617. DsRolepCreateChildTrustObject(
  618. IN HANDLE CallerToken,
  619. IN LSA_HANDLE ParentLsa,
  620. IN LSA_HANDLE ChildLsa,
  621. IN PPOLICY_DNS_DOMAIN_INFO ParentDnsInfo,
  622. IN PPOLICY_DNS_DOMAIN_INFO ChildDnsInfo,
  623. IN PTRUSTED_DOMAIN_AUTH_INFORMATION AuthInfoEx,
  624. IN ULONG Options
  625. )
  626. /*++
  627. Routine Description:
  628. Creates the trusted domain object on the child domain. It does this by reading the
  629. auth info stored on the parent object, swapping its order, and writing it on the child
  630. object
  631. Arguments:
  632. ParentLsa - Handle to the Lsa on the parent Dc
  633. ChildLsa - Handle to our local Lsa
  634. ParentDnsInfo - POLICY_DNS_DOMAIN_INFORMATION from our parent Dc
  635. ChildDnsInfo - POLICY_DNS_DOMAIN_INFORMAITON from ourself
  636. Options - Options that dictate what steps are taken
  637. Returns:
  638. ERROR_SUCCESS - Success
  639. ERROR_INVALID_PARAMETER - A bad results pointer was given
  640. --*/
  641. {
  642. NTSTATUS Status = STATUS_SUCCESS, SecondaryStatus;
  643. TRUSTED_DOMAIN_INFORMATION_EX TDIEx;
  644. PTRUSTED_DOMAIN_INFORMATION_EX ParentEx;
  645. PTRUSTED_DOMAIN_AUTH_INFORMATION ParentAuthData;
  646. LSA_HANDLE TrustedDomain = 0;
  647. UNICODE_STRING ChildDnsName;
  648. //
  649. // Basically, we'll create a trusted domain object with no auth data, and then pull over the
  650. // auth data from our parent.
  651. //
  652. RtlCopyMemory( &TDIEx.Name, &ParentDnsInfo->DnsDomainName,
  653. sizeof( UNICODE_STRING ) );
  654. RtlCopyMemory( &TDIEx.FlatName, &ParentDnsInfo->Name,
  655. sizeof( UNICODE_STRING ) );
  656. TDIEx.Sid = ParentDnsInfo->Sid;
  657. TDIEx.TrustAttributes = TRUST_ATTRIBUTE_WITHIN_FOREST;
  658. //
  659. // Note that if the parent object exists, we'll want to read it's properties, and
  660. // set our trust up accordingly
  661. //
  662. if ( FLAG_ON( Options, DSROLE_DC_PARENT_TRUST_EXISTS ) ) {
  663. Status = ImpLsaQueryTrustedDomainInfoByName( CallerToken,
  664. ParentLsa,
  665. &ChildDnsInfo->DnsDomainName,
  666. TrustedDomainInformationEx,
  667. ( PVOID * )&ParentEx );
  668. if ( !NT_SUCCESS( Status ) ) {
  669. WCHAR *BufDnsDomainName = NULL;
  670. DsRolepUnicodestringtowstr( BufDnsDomainName, ChildDnsInfo->DnsDomainName );
  671. if (BufDnsDomainName) {
  672. DsRolepLogPrint(( DEB_TRACE,
  673. "Failed to read trust info from parent for %ws: 0x%lx\n",
  674. BufDnsDomainName,
  675. Status ));
  676. free(BufDnsDomainName);
  677. }
  678. }
  679. if ( NT_SUCCESS( Status ) ) {
  680. //
  681. // Make sure that the trust on the parent object is correct
  682. //
  683. if ( ChildDnsInfo->Sid == NULL ||
  684. ParentEx->Sid == NULL ||
  685. !RtlEqualSid( ChildDnsInfo->Sid, ParentEx->Sid ) ||
  686. RtlEqualUnicodeString( &ChildDnsInfo->Name, &ParentEx->Name, TRUE ) ) {
  687. Status = STATUS_DOMAIN_TRUST_INCONSISTENT;
  688. }
  689. }
  690. if ( NT_SUCCESS( Status ) ) {
  691. TDIEx.TrustDirection = 0;
  692. TDIEx.TrustType = 0;
  693. if ( FLAG_ON( ParentEx->TrustDirection, TRUST_DIRECTION_INBOUND ) ) {
  694. TDIEx.TrustDirection |= TRUST_DIRECTION_OUTBOUND;
  695. }
  696. if ( FLAG_ON( ParentEx->TrustDirection, TRUST_DIRECTION_OUTBOUND ) ) {
  697. TDIEx.TrustDirection |= TRUST_DIRECTION_INBOUND;
  698. }
  699. TDIEx.TrustType = ParentEx->TrustType;
  700. LsaFreeMemory( ParentEx );
  701. }
  702. DSROLEP_FAIL1( RtlNtStatusToDosError( Status ),
  703. DSROLERES_NO_PARENT_TRUST, ParentDnsInfo->DnsDomainName.Buffer );
  704. } else {
  705. TDIEx.TrustDirection = TRUST_DIRECTION_BIDIRECTIONAL;
  706. TDIEx.TrustType = TRUST_TYPE_UPLEVEL;
  707. RtlCopyMemory( &ChildDnsName, &ChildDnsInfo->DnsDomainName, sizeof( UNICODE_STRING ) );
  708. if ( ChildDnsName.Buffer[ (ChildDnsName.Length - 1) / sizeof(WCHAR)] == L'.' ) {
  709. ChildDnsName.Buffer[ (ChildDnsName.Length - 1) / sizeof(WCHAR)] = UNICODE_NULL;
  710. ChildDnsName.Length -= sizeof(WCHAR);
  711. }
  712. }
  713. if ( NT_SUCCESS( Status ) ) {
  714. {
  715. WCHAR *BufpTDIEx = NULL;
  716. DsRolepLogPrint(( DEB_TRACE, "Creating trusted domain object on child\n" ));
  717. DsRolepUnicodestringtowstr( BufpTDIEx, TDIEx.Name );
  718. if (BufpTDIEx) {
  719. DsRolepLogPrint(( DEB_TRACE,
  720. "\tDnsDomain: %ws\n",
  721. BufpTDIEx,
  722. Status ));
  723. free(BufpTDIEx);
  724. }
  725. DsRolepUnicodestringtowstr( BufpTDIEx, TDIEx.FlatName );
  726. if (BufpTDIEx) {
  727. DsRolepLogPrint(( DEB_TRACE,
  728. "\tFlat name: %ws\n",
  729. BufpTDIEx,
  730. Status ));
  731. free(BufpTDIEx);
  732. }
  733. DsRolepLogPrint(( DEB_TRACE, "\tDirection: %lu\n", TDIEx.TrustDirection ));
  734. DsRolepLogPrint(( DEB_TRACE, "\tType: %lu\n", TDIEx.TrustType ));
  735. DsRolepLogPrint(( DEB_TRACE, "\tAttributes: 0x%lx\n", TDIEx.TrustAttributes ));
  736. }
  737. Status = LsaCreateTrustedDomainEx( ChildLsa,
  738. &TDIEx,
  739. AuthInfoEx,
  740. 0, // no access necessary
  741. &TrustedDomain );
  742. }
  743. if (STATUS_OBJECT_NAME_COLLISION==Status)
  744. {
  745. //
  746. // The object might actually exist, in cases we are upgrading from NT4 etc
  747. //
  748. DsRolepLogPrint(( DEB_TRACE, "Child domain trust object already exists on child\n" ));
  749. //
  750. // Even during NT4 upgrade, we don't want to preserve the quarantine bit, since
  751. // quarantining parent will cause unexpected behavior.
  752. //
  753. Status = DsRolepHandlePreExistingTrustObject(
  754. NULL,
  755. ChildLsa,
  756. &TDIEx,
  757. AuthInfoEx,
  758. FALSE,
  759. &TrustedDomain
  760. );
  761. }
  762. if ( !NT_SUCCESS( Status ) ) {
  763. WCHAR *BufpTDIEx = NULL;
  764. DsRolepUnicodestringtowstr( BufpTDIEx, TDIEx.Name );
  765. if (BufpTDIEx) {
  766. DsRolepLogPrint(( DEB_TRACE,
  767. "Child LsaCreateTrustedDomainEx on %ws failed with 0x%lx\n",
  768. BufpTDIEx,
  769. Status ));
  770. free(BufpTDIEx);
  771. }
  772. DSROLEP_FAIL1( RtlNtStatusToDosError( Status ),
  773. DSROLERES_NO_PARENT_TRUST, ParentDnsInfo->DnsDomainName.Buffer );
  774. } else {
  775. //
  776. // We should have a trusted domain object
  777. //
  778. ASSERT( 0 != TrustedDomain );
  779. if ( TrustedDomain ) {
  780. LsaClose( TrustedDomain );
  781. }
  782. }
  783. return( Status );
  784. }
  785. #pragma warning(pop)
  786. DWORD
  787. DsRolepRemoveTrustedDomainObjects(
  788. IN HANDLE CallerToken,
  789. IN LPWSTR ParentDc,
  790. IN PPOLICY_DNS_DOMAIN_INFO ParentDnsDomainInfo,
  791. IN ULONG Options
  792. )
  793. /*++
  794. Routine Description:
  795. This function will remove the trusted domain objects as a link is being torn down.
  796. It will determine who the trust is with, and remove the local trust to that object.
  797. Optionally, it will also remove the trust from the parent
  798. Arguments:
  799. ParentDc - Optional name of a Dc on our parent
  800. ParentDnsDomainInfo - DNS Domain information from the parent
  801. Options - Whether to remove the parents object or not
  802. Returns:
  803. ERROR_SUCCESS - Success
  804. ERROR_INVALID_PARAMETER - A bad option was provided
  805. --*/
  806. {
  807. NTSTATUS Status = STATUS_SUCCESS;
  808. UNICODE_STRING ParentServer;
  809. HANDLE LocalPolicy = NULL , ParentPolicy = NULL;
  810. HANDLE Trust;
  811. PPOLICY_DNS_DOMAIN_INFO LocalDnsInfo = NULL;
  812. OBJECT_ATTRIBUTES ObjectAttributes;
  813. DSROLEP_CURRENT_OP0( DSROLEEVT_DELETE_TRUST );
  814. //
  815. // If there is no parent Dc, there is no trust...
  816. //
  817. if ( ParentDc == NULL ) {
  818. return( ERROR_SUCCESS );
  819. }
  820. //
  821. // Open both lsas
  822. //
  823. RtlInitUnicodeString( &ParentServer, ParentDc );
  824. RtlZeroMemory( &ObjectAttributes, sizeof( ObjectAttributes ) );
  825. Status = ImpLsaOpenPolicy( CallerToken,
  826. &ParentServer,
  827. &ObjectAttributes,
  828. MAXIMUM_ALLOWED,
  829. &ParentPolicy );
  830. if ( NT_SUCCESS( Status ) ) {
  831. RtlZeroMemory( &ObjectAttributes, sizeof( ObjectAttributes ) );
  832. Status = LsaOpenPolicy( NULL,
  833. &ObjectAttributes,
  834. MAXIMUM_ALLOWED,
  835. &LocalPolicy );
  836. } else {
  837. DsRolepLogPrint(( DEB_TRACE,
  838. "OpenPolicy on %ws failed with 0x%lx\n",
  839. ParentDc,
  840. Status ));
  841. }
  842. //
  843. // Get the DnsTree information from the local machine
  844. //
  845. if ( NT_SUCCESS( Status ) ) {
  846. Status = LsaQueryInformationPolicy( LocalPolicy,
  847. PolicyDnsDomainInformation,
  848. &LocalDnsInfo );
  849. }
  850. //
  851. // Now, open the parent trusted domain object
  852. //
  853. if ( NT_SUCCESS( Status ) && FLAG_ON( Options, DSROLE_DC_DELETE_PARENT_TRUST ) ) {
  854. Status = ImpLsaOpenTrustedDomain( CallerToken,
  855. ParentPolicy,
  856. LocalDnsInfo->Sid,
  857. DELETE,
  858. &Trust );
  859. if ( NT_SUCCESS( Status ) ) {
  860. Status = ImpLsaDelete( CallerToken, Trust );
  861. } else if ( Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
  862. Status = STATUS_SUCCESS;
  863. }
  864. }
  865. //
  866. // Now, the local one
  867. //
  868. if ( NT_SUCCESS( Status ) ) {
  869. Status = LsaOpenTrustedDomain( LocalPolicy,
  870. ParentDnsDomainInfo->Sid,
  871. DELETE,
  872. &Trust );
  873. if ( NT_SUCCESS( Status ) ) {
  874. Status = LsaDelete( Trust );
  875. } else if ( Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
  876. Status = STATUS_SUCCESS;
  877. }
  878. }
  879. //
  880. // Cleanup
  881. //
  882. LsaFreeMemory( LocalDnsInfo );
  883. if ( LocalPolicy ) {
  884. LsaClose( LocalPolicy );
  885. }
  886. if ( ParentPolicy ) {
  887. ImpLsaClose( CallerToken, ParentPolicy );
  888. }
  889. return( RtlNtStatusToDosError( Status ) );
  890. }
  891. DWORD
  892. DsRolepDeleteParentTrustObject(
  893. IN HANDLE CallerToken,
  894. IN LPWSTR ParentDc,
  895. IN PPOLICY_DNS_DOMAIN_INFO ChildDomainInfo
  896. )
  897. /*++
  898. Routine Description:
  899. Deletes the trusted domain object on the parent domain.
  900. Arguments:
  901. ParentDc - Name of a Dc in the parent domain to connect to
  902. ChildDnsInfo - POLICY_DNS_DOMAIN_INFORMAITON from ourself
  903. Returns:
  904. ERROR_SUCCESS - Success
  905. ERROR_INVALID_PARAMETER - A bad results pointer was given
  906. --*/
  907. {
  908. NTSTATUS Status = STATUS_SUCCESS;
  909. UNICODE_STRING ParentServer;
  910. HANDLE ParentPolicy = NULL;
  911. OBJECT_ATTRIBUTES ObjectAttributes;
  912. LSA_HANDLE ParentTrustedDomain, TrustedDomain;
  913. RtlInitUnicodeString( &ParentServer, ParentDc );
  914. RtlZeroMemory( &ObjectAttributes, sizeof( ObjectAttributes ) );
  915. Status = ImpLsaOpenPolicy( CallerToken,
  916. &ParentServer,
  917. &ObjectAttributes,
  918. POLICY_TRUST_ADMIN|POLICY_VIEW_LOCAL_INFORMATION,
  919. &ParentPolicy );
  920. if ( NT_SUCCESS( Status ) ) {
  921. Status = ImpLsaOpenTrustedDomain( CallerToken,
  922. ParentPolicy,
  923. ChildDomainInfo->Sid,
  924. DELETE,
  925. &TrustedDomain );
  926. if ( NT_SUCCESS( Status ) ) {
  927. Status = ImpLsaDelete( CallerToken, TrustedDomain );
  928. if ( !NT_SUCCESS( Status ) ) {
  929. ImpLsaClose( CallerToken, TrustedDomain );
  930. }
  931. }
  932. ImpLsaClose( CallerToken, ParentPolicy );
  933. }
  934. return( RtlNtStatusToDosError( Status ) );
  935. }