Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2534 lines
69 KiB

  1. /*--
  2. Copyright (c) 1997-1997 Microsoft Corporation
  3. Module Name:
  4. trustdom.c
  5. Abstract:
  6. Command line tool for displaying/creating/deleting trust links between 2 domains
  7. Author:
  8. 1-Apr-1997 Mac McLain (macm) Created
  9. 14-Jun-1998 Cristian Ioneci (cristiai) Heavily modified
  10. Environment:
  11. User mode only.
  12. Requires ANSI C extensions: slash-slash comments, long external names.
  13. Revision History:
  14. --*/
  15. #include <nt.h>
  16. #include <ntrtl.h>
  17. #include <nturtl.h>
  18. #include <windows.h>
  19. #include <ntlsa.h>
  20. #include <stdio.h>
  21. #include <string.h>
  22. #include <stdlib.h>
  23. #include <dsgetdc.h>
  24. #include <ntrtl.h>
  25. #include <lmcons.h>
  26. #include <lmapibuf.h>
  27. #include <lmaccess.h>
  28. #include <lmserver.h>
  29. #include <lmerr.h>
  30. #include <string.h>
  31. #define DEFINES_ONLY
  32. #include "res.rc"
  33. //taken from netlibnt.h; resides in netapi32.dll
  34. NTSTATUS
  35. NetpApiStatusToNtStatus(
  36. NET_API_STATUS NetStatus
  37. );
  38. #define DBG 1
  39. //dbgprintf macro: call it like dbgprint(("X:%d\n",i)); //notice the xtra paranthesis!!
  40. #ifdef DBG
  41. #define dbgprintf(a) if(Dbg) resprintf a
  42. #else
  43. #define dbgprintf(a)
  44. #endif
  45. /*-------------------------------------------------------*/
  46. HINSTANCE hInst;
  47. #define RBSZ 4096
  48. WCHAR resbuf[RBSZ];
  49. WCHAR outbuf[RBSZ];
  50. #define RESPRINT_STDOUT 3
  51. /*-------------------------------------------------------*/
  52. //Printf message with format taken from a resource string
  53. // where: 0 - stdout; 1- stderr; 2 - in the 'output' buffer
  54. //take care: the resulting string must be max. RBSZ wchars (see #define above)
  55. int resprintf(int where, UINT ids, ... )
  56. {
  57. va_list parlist;
  58. va_start(parlist,ids);
  59. if(LoadString(hInst,ids,resbuf,RBSZ)==0)
  60. swprintf(resbuf,L"(LoadString failed with 0x%08lx)",GetLastError());
  61. switch(where) {
  62. case 0:
  63. return(vwprintf(resbuf, parlist));
  64. case 1:
  65. return(vfwprintf(stderr, resbuf, parlist));
  66. case 2:
  67. return(vswprintf(outbuf, resbuf, parlist));
  68. case RESPRINT_STDOUT:
  69. return(vfwprintf(stdout, resbuf, parlist));
  70. DEFAULT_UNREACHABLE;
  71. }
  72. }
  73. enum DomInfoType_e { Minimal=0, Primary, DNS };
  74. // Minimal mode is used only for 'localonly' flag...
  75. //Minimal means that the name that was specified on the command line
  76. //(and copied in the ArgDomName member of the _TD_DOM_INFO structure) will
  77. //be the only information available about the target domain (that is, just
  78. //the flat name of the domain). That could happen if the target domain is
  79. //no longer accessible at the moment when the trustdom is run... 'TrustDom'
  80. //will try to do its best in this case...
  81. struct LsaTIshot {
  82. ULONG count;
  83. PLSA_TRUST_INFORMATION pTI;
  84. };
  85. typedef struct _TD_DOM_INFO {
  86. PWSTR pArgDomName; //from the command line...
  87. UNICODE_STRING uMinimalName; //in case it is needed...
  88. LSA_HANDLE Policy;
  89. DWORD majver;
  90. LSA_HANDLE TrustedDomain;
  91. WCHAR DCName[1024];
  92. enum DomInfoType_e DomInfoType;
  93. union {
  94. PPOLICY_PRIMARY_DOMAIN_INFO PrimaryDomainInfo;
  95. PPOLICY_DNS_DOMAIN_INFO DnsDomainInfo;
  96. } u;
  97. PTRUSTED_DOMAIN_INFORMATION_EX pTDIX; //one shot... Lsa memory space
  98. ULONG TDIXcEntries;
  99. struct LsaTIshot *pTIs; //array of TIshots
  100. int nTIs; //no. of TIshots
  101. ULONG TIcEntries;
  102. USER_INFO_1 *pUI1; //one shot...
  103. DWORD UI1cEntries;
  104. } TD_DOM_INFO, *PTD_DOM_INFO;
  105. typedef struct _TD_VERIFY_INFO {
  106. PUNICODE_STRING DisplayName;
  107. PUNICODE_STRING ShortName;
  108. UNICODE_STRING NameBuffer;
  109. NTSTATUS IncomingStatus;
  110. NTSTATUS OutgoingStatus;
  111. } TD_VERIFY_INFO, *PTD_VERIFY_INFO;
  112. //
  113. // Local function prototypes
  114. //
  115. NTSTATUS
  116. GetDomainInfoForDomain(
  117. IN PWSTR DomainName,
  118. IN OPTIONAL PWSTR DCMachineName, // optional DC machine name
  119. IN PTD_DOM_INFO Info,
  120. IN BOOL MitTarget
  121. );
  122. NTSTATUS
  123. GetTrustLinks(
  124. IN PTD_DOM_INFO pInfo
  125. );
  126. VOID
  127. FreeDomainInfo(
  128. IN PTD_DOM_INFO Info
  129. );
  130. //
  131. // Globals
  132. //
  133. BOOLEAN Force = FALSE;
  134. BOOLEAN Nt4 = FALSE;
  135. BOOLEAN Dbg = FALSE;
  136. BOOLEAN SidList = FALSE;
  137. //BOOLEAN Overwritesid = FALSE; actually use Force instead...
  138. ULONG
  139. DisplayErrorMessage(
  140. IN NTSTATUS Status
  141. )
  142. /*++
  143. Routine Description:
  144. This function display the error string for the given error status
  145. Arguments:
  146. NetStatus - Status to display the message for
  147. Return Value:
  148. VOID
  149. --*/
  150. {
  151. ULONG Size = 0;
  152. PWSTR DisplayString;
  153. ULONG Options = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM;
  154. Size = FormatMessage( Options,
  155. NULL,
  156. RtlNtStatusToDosError( Status ),
  157. MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
  158. ( LPTSTR )&DisplayString,
  159. 0,
  160. NULL );
  161. if ( Size != 0 ) {
  162. fprintf( stdout, "%ws", DisplayString );
  163. LocalFree( DisplayString );
  164. }
  165. return( Size );
  166. }
  167. VOID
  168. Usage (
  169. VOID
  170. )
  171. {
  172. resprintf(1,IDS_USAGE,VER_FILEVERSION_LSTR);
  173. }
  174. /*---------------------------- printSID --------------------------*/
  175. BOOL
  176. PrintSID(
  177. IN PSID s
  178. )
  179. {
  180. int i;
  181. BOOL r=TRUE;
  182. SID_IDENTIFIER_AUTHORITY *a;
  183. if(s==NULL) {
  184. printf("<NULL sid>");
  185. return(FALSE);
  186. }
  187. if (!IsValidSid(s)) {
  188. printf("<invalid sid>:");
  189. r=FALSE;
  190. }
  191. a = GetSidIdentifierAuthority(s);
  192. // printf("S-0x1-%02x%02x%02x%02x%02x%02x",
  193. // a->Value[0], a->Value[1],
  194. // a->Value[2], a->Value[3],
  195. // a->Value[4], a->Value[5]);
  196. printf("S-0x1-");
  197. for(i=0; i<6; i++)
  198. if(a->Value[i]>0)
  199. break;
  200. if(i==6) // hmmm... all zeroes?
  201. printf("0"); // out one zero then
  202. else {
  203. for( ; i<6; i++) // else dump the remaining ones
  204. printf("%02x",a->Value[i]);
  205. }
  206. for (i = 0; i < (int)(*GetSidSubAuthorityCount(s)); i++) {
  207. printf("-%lx", *GetSidSubAuthority(s, i));
  208. }
  209. return(r);
  210. }
  211. NTSTATUS
  212. GenerateRandomSID(
  213. OUT PSID *pSID
  214. )
  215. {
  216. NTSTATUS Status = STATUS_SUCCESS;
  217. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  218. LARGE_INTEGER CurrentTime;
  219. NtQuerySystemTime(&CurrentTime);
  220. Status = RtlAllocateAndInitializeSid(
  221. &NtAuthority,
  222. 4,
  223. SECURITY_NT_NON_UNIQUE,
  224. 0,
  225. CurrentTime.LowPart,
  226. CurrentTime.HighPart,
  227. 0,0,0,0,
  228. pSID
  229. );
  230. if (!NT_SUCCESS(Status))
  231. {
  232. *pSID=NULL;
  233. resprintf(0,IDS_GENERATERANDOMSID_F,Status);
  234. }
  235. return(Status);
  236. }
  237. //--------------------------zapchr------------------------------------
  238. BOOL zapchr(WCHAR *s, // zap specified character from the end of string
  239. WCHAR c, // usefull to cut things like '\n' or '\\'
  240. WCHAR rc) // rc is the char to replace with
  241. { WCHAR *p;
  242. if((p=wcsrchr(s,c))!=NULL) {
  243. *p=rc;
  244. return(TRUE); // found smth to cut...
  245. }
  246. return(FALSE); // the string was "clean"...
  247. }
  248. /*----------------------------------------------------------------------------*/
  249. BOOL GetPassword(WCHAR *passwd, size_t n)
  250. {
  251. /* turn off console echo & read in the password */
  252. HANDLE console;
  253. DWORD mode;
  254. *passwd=L'\0';
  255. if((console = GetStdHandle(STD_INPUT_HANDLE))==INVALID_HANDLE_VALUE)
  256. return(FALSE);
  257. if (! GetConsoleMode(console, &mode))
  258. return(FALSE);
  259. if (! SetConsoleMode(console, (mode & ~ENABLE_ECHO_INPUT)))
  260. return(FALSE);
  261. //fwprintf(stderr, L"Password : ");
  262. resprintf(1,IDS_PASSWORD_PROMPT);
  263. if (!fgetws(passwd, n, stdin))
  264. return(FALSE);
  265. zapchr(passwd,L'\n',L'\0');
  266. if (! SetConsoleMode(console, mode))
  267. return(FALSE);
  268. if(!CloseHandle(console))
  269. return(FALSE);
  270. fwprintf(stderr,L"\n");
  271. return(TRUE);
  272. }
  273. //UNICODE_STRING uMinimalName; not used anymore... added a field with same name inside each
  274. //TD_DOM_INFO structure that will be used instead... in this way two consecutive calls
  275. //*** FOR TWO STRUCTURES*** will not overwrite it.
  276. //------------------GetFlatName---------------------------
  277. PLSA_UNICODE_STRING GetFlatName(IN PTD_DOM_INFO pInfo)
  278. {
  279. switch(pInfo->DomInfoType) {
  280. case DNS:
  281. return(&pInfo->u.DnsDomainInfo->Name);
  282. case Primary:
  283. return(&pInfo->u.PrimaryDomainInfo->Name);
  284. default: //Minimal
  285. RtlInitUnicodeString(&pInfo->uMinimalName,pInfo->pArgDomName);
  286. return(&pInfo->uMinimalName);
  287. }
  288. }
  289. //------------------GetName--------------------------------
  290. PLSA_UNICODE_STRING GetName(IN PTD_DOM_INFO pInfo)
  291. {
  292. //simpler, just a little bit slower... (xtra call)
  293. // if(pInfo->DomInfoType==DNS)
  294. // return(&pInfo->u.DnsDomainInfo->DnsDomainName);
  295. //
  296. // return(GetFlatName(pInfo));
  297. switch(pInfo->DomInfoType) {
  298. case DNS:
  299. return(&pInfo->u.DnsDomainInfo->DnsDomainName);
  300. case Primary:
  301. return(&pInfo->u.PrimaryDomainInfo->Name);
  302. default: //Minimal
  303. RtlInitUnicodeString(&pInfo->uMinimalName,pInfo->pArgDomName);
  304. return(&pInfo->uMinimalName);
  305. }
  306. }
  307. PSID GetSid(IN PTD_DOM_INFO pInfo)
  308. {
  309. PSID ReturnSid = NULL;
  310. switch(pInfo->DomInfoType) {
  311. case DNS:
  312. ReturnSid = pInfo->u.DnsDomainInfo->Sid;
  313. break;
  314. case Primary:
  315. ReturnSid = pInfo->u.PrimaryDomainInfo->Sid;
  316. break;
  317. }
  318. return( ReturnSid );
  319. }
  320. WCHAR SrvName[1024];
  321. //----------------MakeSrvName-------------------------------
  322. PWSTR MakeSrvName(IN PWSTR Name) //add slashes at the beginning
  323. {
  324. swprintf(SrvName,L"\\\\%ws",Name);
  325. if(SrvName[0]==L'\0')
  326. return(NULL);
  327. return(SrvName);
  328. }
  329. WCHAR Domain[1024];
  330. //----------------AddDlrToDomainName-------------------------
  331. PWSTR AddDlrToDomainName(IN PTD_DOM_INFO pInfo)
  332. {
  333. swprintf(Domain,L"%wZ$",GetFlatName(pInfo));
  334. return(Domain);
  335. }
  336. WCHAR CutDlrDomain[1024];
  337. //----------------CutDlrFromName-----------------------------
  338. PWSTR CutDlrFromName(IN PWSTR Name)
  339. {
  340. wcscpy(CutDlrDomain,Name);
  341. zapchr(CutDlrDomain,L'$',L'\0');
  342. return(CutDlrDomain);
  343. }
  344. WCHAR secret[1024];
  345. LSA_UNICODE_STRING uSecret;
  346. //---------------------MakeSecretName------------------
  347. PLSA_UNICODE_STRING MakeSecretName(IN PTD_DOM_INFO pInfo)
  348. {
  349. swprintf(secret,L"G$$%wZ",GetFlatName(pInfo));
  350. RtlInitUnicodeString(&uSecret,secret);
  351. return(&uSecret);
  352. }
  353. //start section inserted from Mac (11/05/1998(Thu) 17:08:53)
  354. NTSTATUS
  355. VerifyIndividualTrust(
  356. IN PSID InboundDomainSid,
  357. IN PUNICODE_STRING InboundDomainName,
  358. IN PLSA_HANDLE OutboundHandle,
  359. IN PWSTR OutboundServer,
  360. IN OUT PNTSTATUS VerifyStatus
  361. )
  362. /*++
  363. Routine Description:
  364. This routine will verify a single trust in the one direction only.
  365. Arguments:
  366. InboundDomainSid -- Sid of the inbound side of the trust
  367. OutboundHandle -- Open policy handle to a domain controller on the outbound side
  368. OutboundServer -- Name of the domian controller on the outbound side
  369. VerifyStatus -- Status returned from the verification attempt
  370. Return Value:
  371. STATUS_SUCCESS -- Success
  372. STATUS_INVALID_SID -- The specified domain sid was invalid
  373. --*/
  374. {
  375. NTSTATUS Status = STATUS_SUCCESS;
  376. DWORD SidBuff[ sizeof( SID ) / sizeof( DWORD ) + 5 ];
  377. PSID DomAdminSid = ( PSID )SidBuff;
  378. PLSA_REFERENCED_DOMAIN_LIST Domains = NULL;
  379. PLSA_TRANSLATED_NAME Names = NULL;
  380. NET_API_STATUS NetStatus;
  381. PNETLOGON_INFO_2 NetlogonInfo2 = NULL;
  382. //
  383. // Assume the trust is invalid until we can prove otherwise.
  384. //
  385. *VerifyStatus = STATUS_TRUSTED_DOMAIN_FAILURE;
  386. ASSERT( RtlValidSid( InboundDomainSid ) );
  387. if ( !RtlValidSid( InboundDomainSid ) ) {
  388. return( STATUS_INVALID_SID );
  389. }
  390. //
  391. // Check netlogons secure channel
  392. //
  393. if ( NT_SUCCESS( Status ) ) {
  394. NetStatus = I_NetLogonControl2( OutboundServer,
  395. NETLOGON_CONTROL_TC_QUERY,
  396. 2,
  397. ( LPBYTE )&InboundDomainName->Buffer,
  398. ( LPBYTE *)&NetlogonInfo2 );
  399. if ( NetStatus == NERR_Success ) {
  400. NetStatus = NetlogonInfo2->netlog2_pdc_connection_status;
  401. NetApiBufferFree( NetlogonInfo2 );
  402. if ( NetStatus != NERR_Success ) {
  403. NetStatus = I_NetLogonControl2( OutboundServer,
  404. NETLOGON_CONTROL_REDISCOVER,
  405. 2,
  406. ( LPBYTE )&InboundDomainName->Buffer,
  407. ( LPBYTE *)&NetlogonInfo2 );
  408. }
  409. }
  410. *VerifyStatus = NetpApiStatusToNtStatus( NetStatus );
  411. }
  412. //
  413. // Now, try a lookup
  414. //
  415. if ( NT_SUCCESS( Status ) && NT_SUCCESS( *VerifyStatus ) ) {
  416. //
  417. // Build the domain admins sid for the inbound side of the trust
  418. //
  419. RtlCopyMemory( DomAdminSid,
  420. InboundDomainSid,
  421. RtlLengthSid( InboundDomainSid ) );
  422. ( ( PISID )( DomAdminSid ) )->SubAuthorityCount++;
  423. *( RtlSubAuthoritySid( DomAdminSid,
  424. *( RtlSubAuthorityCountSid( InboundDomainSid ) ) ) ) =
  425. DOMAIN_GROUP_RID_ADMINS;
  426. //
  427. // Now, we'll simply do a remote lookup, and ensure that we get back success
  428. //
  429. Status = LsaLookupSids( OutboundHandle,
  430. 1,
  431. &DomAdminSid,
  432. &Domains,
  433. &Names );
  434. if ( NT_SUCCESS( Status ) ) {
  435. LsaFreeMemory( Domains );
  436. LsaFreeMemory( Names );
  437. *VerifyStatus = STATUS_SUCCESS;
  438. } else if ( Status == STATUS_NONE_MAPPED ) {
  439. *VerifyStatus = STATUS_TRUSTED_DOMAIN_FAILURE;
  440. Status = STATUS_SUCCESS;
  441. } else {
  442. *VerifyStatus = Status;
  443. }
  444. //
  445. // If all of that worked, check netlogons secure channel
  446. //
  447. if ( NT_SUCCESS( Status ) && NT_SUCCESS( *VerifyStatus ) ) {
  448. NetStatus = I_NetLogonControl2( OutboundServer,
  449. NETLOGON_CONTROL_TC_QUERY,
  450. 2,
  451. ( LPBYTE )&InboundDomainName->Buffer,
  452. ( LPBYTE *)&NetlogonInfo2 );
  453. if ( NetStatus == NERR_Success ) {
  454. NetStatus = NetlogonInfo2->netlog2_pdc_connection_status;
  455. NetApiBufferFree( NetlogonInfo2 );
  456. if ( NetStatus != NERR_Success ) {
  457. NetStatus = I_NetLogonControl2( OutboundServer,
  458. NETLOGON_CONTROL_REDISCOVER,
  459. 2,
  460. ( LPBYTE )&InboundDomainName->Buffer,
  461. ( LPBYTE *)&NetlogonInfo2 );
  462. }
  463. }
  464. *VerifyStatus = NetpApiStatusToNtStatus( NetStatus );
  465. }
  466. }
  467. return( Status );
  468. }
  469. NTSTATUS
  470. VerifyTrustInbound(
  471. IN PTD_DOM_INFO LocalDomain,
  472. IN PUNICODE_STRING RemoteDomain,
  473. IN OUT PNTSTATUS VerifyStatus
  474. )
  475. {
  476. NTSTATUS Status = STATUS_SUCCESS;
  477. TD_DOM_INFO RemoteTrustInfo;
  478. WCHAR DCname[MAX_PATH + 1]= { L'\0' };
  479. RtlZeroMemory( &RemoteTrustInfo, sizeof( RemoteTrustInfo ) );
  480. Status = GetDomainInfoForDomain( RemoteDomain->Buffer, NULL, &RemoteTrustInfo, FALSE );
  481. if ( NT_SUCCESS( Status ) ) {
  482. Status= VerifyIndividualTrust( GetSid( LocalDomain ),
  483. GetName( LocalDomain ),
  484. RemoteTrustInfo.Policy,
  485. RemoteTrustInfo.DCName,
  486. VerifyStatus );
  487. FreeDomainInfo( &RemoteTrustInfo );
  488. } else {
  489. *VerifyStatus = Status;
  490. }
  491. return( Status );
  492. }
  493. NTSTATUS
  494. VerifyTrustOutbound(
  495. IN PTD_DOM_INFO LocalDomain,
  496. IN PUNICODE_STRING RemoteDomain,
  497. IN OUT PNTSTATUS VerifyStatus
  498. )
  499. {
  500. NTSTATUS Status = STATUS_SUCCESS;
  501. TD_DOM_INFO RemoteTrustInfo;
  502. RtlZeroMemory( &RemoteTrustInfo, sizeof( RemoteTrustInfo ) );
  503. Status = GetDomainInfoForDomain( RemoteDomain->Buffer, NULL, &RemoteTrustInfo, FALSE );
  504. if ( NT_SUCCESS( Status ) ) {
  505. Status= VerifyIndividualTrust( GetSid( &RemoteTrustInfo ),
  506. GetName( &RemoteTrustInfo ),
  507. LocalDomain->Policy,
  508. LocalDomain->DCName,
  509. VerifyStatus );
  510. FreeDomainInfo( &RemoteTrustInfo );
  511. } else {
  512. *VerifyStatus = Status;
  513. }
  514. return( Status );
  515. }
  516. NTSTATUS
  517. VerifyTrusts(
  518. IN PWSTR DomainName,
  519. IN OPTIONAL PWSTR DCMachineName // optional DC machine name
  520. )
  521. /*++
  522. Routine Description:
  523. This routine will verify the existing trusts with all other NT domains, and display the
  524. results.
  525. Arguments:
  526. DomainName -- OPTIONAL name of the domain on which to verify the information
  527. Return Value:
  528. STATUS_SUCCESS -- Success
  529. STATUS_INSUFFICIENT_RESOURCES -- A memory allocation failed
  530. --*/
  531. {
  532. NTSTATUS Status = STATUS_SUCCESS;
  533. TD_DOM_INFO TrustInfo;
  534. PTD_VERIFY_INFO VerifyList = NULL;
  535. ULONG VerifyCount = 0, VerifyIndex = 0, i, j;
  536. BOOLEAN InvalidIncoming = FALSE, InvalidOutgoing = FALSE, Valid = FALSE;
  537. UNICODE_STRING *LocalDomainName = NULL, SamNameAsDomain;
  538. WCHAR *AccountTrunc;
  539. RtlZeroMemory( &TrustInfo, sizeof( TrustInfo ) );
  540. Status = GetDomainInfoForDomain( DomainName, DCMachineName, &TrustInfo, FALSE );
  541. if ( NT_SUCCESS( Status ) ) {
  542. Status = GetTrustLinks( &TrustInfo );
  543. }
  544. if ( !NT_SUCCESS( Status ) ) {
  545. goto VerifyExit;
  546. }
  547. LocalDomainName = GetName( &TrustInfo );
  548. //
  549. // Allocate a list of verify information to correspond to the list we enumerated
  550. //
  551. VerifyCount = max( TrustInfo.TDIXcEntries, TrustInfo.UI1cEntries + TrustInfo.TIcEntries );
  552. VerifyList = ( PTD_VERIFY_INFO )LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT,
  553. VerifyCount * sizeof( TD_VERIFY_INFO ) );
  554. if ( !VerifyList ) {
  555. Status = STATUS_INSUFFICIENT_RESOURCES;
  556. goto VerifyExit;
  557. }
  558. //
  559. // Now, do the verification.
  560. //
  561. if ( TrustInfo.TDIXcEntries ) {
  562. for ( i = 0; i < TrustInfo.TDIXcEntries; i++ ) {
  563. if ( TrustInfo.pTDIX[ i ].TrustType == TRUST_TYPE_DOWNLEVEL ||
  564. TrustInfo.pTDIX[ i ].TrustType == TRUST_TYPE_UPLEVEL ) {
  565. VerifyList[ VerifyIndex ].DisplayName = &TrustInfo.pTDIX[ i ].Name;
  566. VerifyList[ VerifyIndex ].ShortName = &TrustInfo.pTDIX[ i ].FlatName;
  567. resprintf( RESPRINT_STDOUT, IDS_VERIFY_CHECK,
  568. LocalDomainName,
  569. VerifyList[ VerifyIndex ].DisplayName );
  570. if ( ( TrustInfo.pTDIX[ i ].TrustDirection & TRUST_DIRECTION_INBOUND ) ) {
  571. Status = VerifyTrustInbound( &TrustInfo,
  572. &TrustInfo.pTDIX[ i ].Name,
  573. &VerifyList[ VerifyIndex ].IncomingStatus );
  574. }
  575. if ( ( TrustInfo.pTDIX[ i ].TrustDirection & TRUST_DIRECTION_OUTBOUND ) &&
  576. Status != STATUS_NO_SUCH_DOMAIN ) {
  577. Status = VerifyTrustOutbound( &TrustInfo,
  578. &TrustInfo.pTDIX[ i ].Name,
  579. &VerifyList[ VerifyIndex ].OutgoingStatus );
  580. }
  581. if ( NT_SUCCESS( VerifyList[ VerifyIndex ].OutgoingStatus ) &&
  582. NT_SUCCESS( VerifyList[ VerifyIndex ].IncomingStatus ) ) {
  583. Valid = TRUE;
  584. } else {
  585. if ( !NT_SUCCESS( VerifyList[ VerifyIndex ].OutgoingStatus ) ) {
  586. InvalidOutgoing = TRUE;
  587. }
  588. if ( !NT_SUCCESS( VerifyList[ VerifyIndex ].IncomingStatus ) ) {
  589. InvalidIncoming = TRUE;
  590. }
  591. }
  592. VerifyIndex++;
  593. }
  594. Status = STATUS_SUCCESS;
  595. }
  596. } else {
  597. //
  598. // Going to have to do the old NT4 style.
  599. //
  600. //for ( i = 0; i < TrustInfo.TIcEntries; i++ ) {
  601. int shot;
  602. for ( VerifyIndex=0, shot=0; shot<TrustInfo.nTIs; shot++)
  603. for(i=0; i<TrustInfo.pTIs[shot].count; i++) {
  604. VerifyList[ VerifyIndex ].DisplayName = &TrustInfo.pTIs[shot].pTI[ i ].Name;
  605. VerifyList[ VerifyIndex ].ShortName = &TrustInfo.pTIs[shot].pTI[ i ].Name;
  606. resprintf( RESPRINT_STDOUT, IDS_VERIFY_CHECK,
  607. LocalDomainName,
  608. VerifyList[ VerifyIndex ].DisplayName );
  609. Status = VerifyTrustOutbound( &TrustInfo,
  610. &TrustInfo.pTIs[shot].pTI[ i ].Name,
  611. &VerifyList[ VerifyIndex ].OutgoingStatus );
  612. if ( !NT_SUCCESS( VerifyList[ VerifyIndex ].OutgoingStatus ) ) {
  613. InvalidOutgoing = TRUE;
  614. }
  615. VerifyIndex++;
  616. }
  617. //
  618. // Now, the same with the sam account names
  619. //
  620. for ( i = 0; i < TrustInfo.UI1cEntries; i++ ) {
  621. //
  622. // Shorten the account name to be a domain name
  623. //
  624. AccountTrunc = &TrustInfo.pUI1[ i ].usri1_name[
  625. wcslen( TrustInfo.pUI1[ i ].usri1_name ) - 1 ];
  626. *AccountTrunc = UNICODE_NULL;
  627. //
  628. // See if we already have an entry for this in our verified list
  629. //
  630. RtlInitUnicodeString( &SamNameAsDomain, TrustInfo.pUI1[ i ].usri1_name );
  631. for ( j = 0; j < VerifyIndex; j++ ) {
  632. if ( RtlEqualUnicodeString( &SamNameAsDomain,
  633. VerifyList[ j ].ShortName, TRUE ) ) {
  634. break;
  635. }
  636. }
  637. if ( j == VerifyIndex ) {
  638. RtlCopyMemory( &VerifyList[ j ].NameBuffer, &SamNameAsDomain,
  639. sizeof( UNICODE_STRING ) );
  640. VerifyList[ j ].DisplayName = &VerifyList[ j ].NameBuffer;
  641. VerifyList[ j ].ShortName = &VerifyList[ j ].NameBuffer;
  642. VerifyIndex++;
  643. }
  644. resprintf( RESPRINT_STDOUT, IDS_VERIFY_CHECK,
  645. LocalDomainName,
  646. &SamNameAsDomain );
  647. Status = VerifyTrustInbound( &TrustInfo,
  648. &SamNameAsDomain,
  649. &VerifyList[ j ].IncomingStatus );
  650. if ( !NT_SUCCESS( VerifyList[ j ].IncomingStatus ) ) {
  651. InvalidIncoming = TRUE;
  652. }
  653. *AccountTrunc = L'$';
  654. }
  655. //
  656. // Now, walk the list and see if we have any valid domain pairs
  657. //
  658. for ( i = 0; i < VerifyIndex; i++ ) {
  659. if ( NT_SUCCESS( VerifyList[ i ].IncomingStatus ) &&
  660. NT_SUCCESS( VerifyList[ i ].OutgoingStatus ) ) {
  661. Valid = TRUE;
  662. break;
  663. }
  664. }
  665. }
  666. //
  667. // Display the list of valid trusts
  668. //
  669. if ( Valid ) {
  670. resprintf( RESPRINT_STDOUT, IDS_VERIFY_VALID );
  671. for ( i = 0; i < VerifyIndex; i++ ) {
  672. if ( NT_SUCCESS( VerifyList[ i ].IncomingStatus ) &&
  673. NT_SUCCESS( VerifyList[ i ].OutgoingStatus ) ) {
  674. fprintf(stdout, "%wZ\n", VerifyList[ i ].DisplayName );
  675. }
  676. }
  677. }
  678. if ( InvalidIncoming ) {
  679. resprintf( RESPRINT_STDOUT, IDS_VERIFY_INVALID_INCOMING );
  680. for ( i = 0; i < VerifyIndex; i++ ) {
  681. if ( !NT_SUCCESS( VerifyList[ i ].IncomingStatus ) ) {
  682. fprintf( stdout, "%wZ - ", VerifyList[ i ].DisplayName );
  683. if ( DisplayErrorMessage( VerifyList[ i ].IncomingStatus ) == 0 ) {
  684. resprintf( RESPRINT_STDOUT, IDS_VERIFY_UNMAPPABLE,
  685. VerifyList[ i ].IncomingStatus );
  686. }
  687. }
  688. }
  689. }
  690. if ( InvalidOutgoing ) {
  691. resprintf( RESPRINT_STDOUT, IDS_VERIFY_INVALID_OUTGOING );
  692. for ( i = 0; i < VerifyIndex; i++ ) {
  693. if ( !NT_SUCCESS( VerifyList[ i ].OutgoingStatus ) ) {
  694. fprintf( stdout, "%wZ - ", VerifyList[ i ].DisplayName );
  695. if ( DisplayErrorMessage( VerifyList[ i ].OutgoingStatus ) == 0 ) {
  696. resprintf( RESPRINT_STDOUT, IDS_VERIFY_UNMAPPABLE,
  697. VerifyList[ i ].OutgoingStatus );
  698. }
  699. }
  700. }
  701. }
  702. Status = STATUS_SUCCESS;
  703. VerifyExit:
  704. LocalFree( VerifyList );
  705. FreeDomainInfo( &TrustInfo );
  706. return( Status );
  707. }
  708. //end section insert from Mac (11/05/1998(Thu) 17:09:39)
  709. NTSTATUS
  710. GetDomainInfoForDomain(
  711. IN PWSTR DomainName,
  712. IN OPTIONAL PWSTR DCMachineName, // optional DC machine name
  713. IN PTD_DOM_INFO Info,
  714. BOOL MitTarget // TRUE if this call is made for the B domain in a A <-> B Mit type trust link
  715. )
  716. /*++
  717. Routine Description:
  718. Tries to fill as much as possible of the TD_DOM_INFO structure for the given domain;
  719. For a NT4 DC, the DNS name does not exist
  720. Arguments:
  721. DomainName -- Optional domain to conect to
  722. Info -- Information structure to fill in
  723. Return Value:
  724. STATUS_SUCCESS -- Success
  725. STATUS_NO_SUCH_DOMAIN -- No server could be located for the domain
  726. --*/
  727. {
  728. NET_API_STATUS netstatus=NERR_Success;
  729. NTSTATUS Status = STATUS_SUCCESS;
  730. PWSTR pMachine=NULL;
  731. DWORD dwErr;
  732. UNICODE_STRING Server;
  733. // UNICODE_STRING uString;
  734. // PLSA_UNICODE_STRING puDomName;
  735. //
  736. OBJECT_ATTRIBUTES ObjectAttributes;
  737. PDOMAIN_CONTROLLER_INFO DCInfo = NULL;
  738. SERVER_INFO_101 *p101 = NULL;
  739. PSID sid=NULL;
  740. WCHAR *DCInfostr=L"";
  741. Info->DomInfoType=Minimal;
  742. Info->pArgDomName=DomainName;
  743. Info->majver=0; // assume nothing... or a Unix machine... (for a MIT trust)
  744. Info->DCName[0]=L'\0';
  745. if(MitTarget)
  746. return(STATUS_NO_SUCH_DOMAIN);
  747. resprintf(2,IDS_LOCAL); // printed to outbuf....
  748. if ( (DomainName != NULL && DomainName[0]!=L'\0') || Nt4 ) { // try to get local machine name for an Nt4 style operation...
  749. if(DCMachineName == NULL || DCMachineName[0]==L'\0') {
  750. dwErr = DsGetDcName( NULL, (LPCWSTR)DomainName, NULL, NULL,
  751. DS_DIRECTORY_SERVICE_PREFERRED | DS_WRITABLE_REQUIRED,
  752. &DCInfo );
  753. if ( dwErr == ERROR_SUCCESS ) {
  754. wcscpy(Info->DCName,DCInfo->DomainControllerName + 2);
  755. pMachine=Info->DCName;
  756. //set the version
  757. if((DCInfo->Flags&(DS_DS_FLAG|DS_WRITABLE_FLAG))==DS_WRITABLE_FLAG)
  758. Info->majver=4;
  759. else Info->majver=5;
  760. dbgprintf((0,IDS_DSGETDCNAME_DC_D,DomainName!=NULL?DomainName:outbuf,Info->DCName)); //,DCInfo->Flags));
  761. } else {
  762. Status = STATUS_NO_SUCH_DOMAIN;
  763. resprintf(0,IDS_DSGETDCNAME_F,DomainName!=NULL?DomainName:outbuf,dwErr);
  764. if(Force)
  765. resprintf(0,IDS_DSGETDCNAME_FFORCE);
  766. else resprintf(0,IDS_DSGETDCNAME_FRET,Status);
  767. }
  768. }
  769. else {
  770. wcscpy(Info->DCName,DCMachineName);
  771. pMachine=Info->DCName;
  772. dbgprintf((0,IDS_DSGETDCNAME_DC_D,DomainName!=NULL?DomainName:outbuf,Info->DCName));
  773. //now trying to get version using some other method than based on the flags returned by DsGetDcName...
  774. netstatus = NetServerGetInfo( MakeSrvName(pMachine), 101, ( LPBYTE *) &p101 );
  775. if(netstatus != NERR_Success) {
  776. Status = STATUS_UNSUCCESSFUL;
  777. fprintf(stderr,"NetServerGetInfo (101) failed: err 0x%08lx;\n"
  778. " ...now returning Status 0x%08lx (STATUS_UNSUCCESSFUL)\n",
  779. netstatus,Status);
  780. goto cleanup;
  781. }
  782. Info->majver=(p101->sv101_version_major & MAJOR_VERSION_MASK);
  783. }
  784. }
  785. RtlInitUnicodeString( &Server, Info->DCName );
  786. if(Nt4) { // force Nt4 style
  787. Info->majver=4;
  788. dbgprintf( (0, IDS_FORCENT4, DomainName!=NULL?DomainName:outbuf) );
  789. }
  790. // if ( NT_SUCCESS( Status ) )
  791. // {
  792. //
  793. // netstatus = NetServerGetInfo( pMachine, 101, ( LPBYTE *) &p101 );
  794. // if(netstatus != NERR_Success) {
  795. // Status = STATUS_UNSUCCESSFUL;
  796. // fprintf(stderr,"NetServerGetInfo (101) failed: err 0x%08lx;\n"
  797. // " ...now returning Status 0x%08lx (STATUS_UNSUCCESSFUL)\n",
  798. // netstatus,Status);
  799. // goto cleanup;
  800. // }
  801. // Info->majver=(p101->sv101_version_major & MAJOR_VERSION_MASK);
  802. // }
  803. if ( NT_SUCCESS( Status ) ) {
  804. RtlZeroMemory( &ObjectAttributes, sizeof( ObjectAttributes ) );
  805. Status = LsaOpenPolicy( DomainName == NULL ? NULL : &Server,
  806. &ObjectAttributes,
  807. MAXIMUM_ALLOWED,
  808. &Info->Policy
  809. );
  810. if(!NT_SUCCESS(Status)) {
  811. resprintf(0,IDS_LSAOPENPOLICY_F1, (Info->DCName[0]==L'\0')?outbuf:Info->DCName);
  812. if ( Status == STATUS_ACCESS_DENIED)
  813. resprintf(0,IDS_ACCESS_DENIED);
  814. else resprintf(0,IDS_ERROR_FORMAT,Status);
  815. goto cleanup;
  816. }
  817. Info->DomInfoType=DNS;
  818. DCInfostr=L"DNS";
  819. Status = LsaQueryInformationPolicy( Info->Policy,
  820. PolicyDnsDomainInformation,
  821. &(Info->u.DnsDomainInfo ) //the SID is in here...
  822. );
  823. dbgprintf( (0,IDS_GETDOMAININFOFORDOMAIN_D, DomainName!=NULL?DomainName:outbuf, DCInfostr, Status ));
  824. if( !NT_SUCCESS( Status ) || Nt4) { // try at least Primary....
  825. Info->majver=4;
  826. DCInfostr=L"Primary";
  827. dbgprintf( (0,IDS_PRIMARY_D) );
  828. Info->DomInfoType=Primary;
  829. Status = LsaQueryInformationPolicy( Info->Policy,
  830. PolicyPrimaryDomainInformation,
  831. &(Info->u.PrimaryDomainInfo ) //the SID is in here...
  832. );
  833. dbgprintf( (0,IDS_GETDOMAININFOFORDOMAIN_D, DomainName!=NULL?DomainName:outbuf, DCInfostr, Status ) );
  834. }
  835. else {
  836. Info->majver=5;
  837. }
  838. switch(Info->DomInfoType) {
  839. case DNS: sid = Info->u.DnsDomainInfo->Sid;
  840. break;
  841. case Primary: sid = Info->u.PrimaryDomainInfo->Sid;
  842. break;
  843. }
  844. if(Dbg) {
  845. printf("Domain %ws Sid=",DCInfostr);
  846. PrintSID(sid);
  847. printf("\n");
  848. }
  849. }
  850. if(Info->DomInfoType==DNS)
  851. dbgprintf( (0,IDS_DOMAINNAMED,&(Info->u.DnsDomainInfo->DnsDomainName) ) );
  852. if ( !NT_SUCCESS( Status ) )
  853. //well...
  854. goto cleanup;
  855. //...
  856. cleanup:
  857. if(DCInfo!=NULL)
  858. NetApiBufferFree( DCInfo );
  859. if(p101!=NULL)
  860. NetApiBufferFree( p101 );
  861. return( Status );
  862. }
  863. VOID
  864. FreeDomainInfo(
  865. IN PTD_DOM_INFO Info
  866. )
  867. /*++
  868. Routine Description:
  869. Frees the info returned from GetDomainInfoForDomain
  870. Arguments:
  871. Info -- Information structure to free
  872. Return Value:
  873. STATUS_SUCCESS -- Success
  874. --*/
  875. {
  876. int i;
  877. if ( Info->Policy ) {
  878. LsaClose( Info->Policy );
  879. Info->Policy=NULL;
  880. }
  881. if ( Info->u.DnsDomainInfo != NULL )
  882. LsaFreeMemory( Info->u.DnsDomainInfo );
  883. // Info->u.DnsDomainInfo is inside an union with Info->u.PrimaryDomainInfo
  884. //on the same position
  885. if(Info->pTDIX!=NULL)
  886. LsaFreeMemory(Info->pTDIX);
  887. //if there's an array of pointers to TI shots returned from LsaEnumerateTrustedDomains...
  888. if(Info->pTIs!=NULL) {
  889. for(i=0; i<Info->nTIs; i++)
  890. LsaFreeMemory(Info->pTIs[i].pTI);
  891. }
  892. if(Info->pUI1!=NULL)
  893. NetApiBufferFree(Info->pUI1);
  894. }
  895. NTSTATUS
  896. GetTrustLinks(
  897. IN PTD_DOM_INFO pInfo
  898. )
  899. /*++
  900. Fills an array of trust links information.
  901. Usually that information will be printed in the form:
  902. domain_name, trust direction, type, attributes
  903. )
  904. --*/
  905. {
  906. NET_API_STATUS netstatus=NERR_Success;
  907. NTSTATUS Status = STATUS_SUCCESS;
  908. LSA_ENUMERATION_HANDLE EnumerationContext = 0;
  909. //needed for NT4 enumeration...
  910. DWORD UIRead=0L;
  911. DWORD UITotal=0L;
  912. DWORD reshandle=0; // Put 0 for enumeration handles !!!!
  913. //A value like INVALID_HANDLE_VALUE (that is -1) would make the NetUserEnum to return 0 users...
  914. if(pInfo->majver>=5) {
  915. Status = LsaEnumerateTrustedDomainsEx( pInfo->Policy,
  916. &EnumerationContext,
  917. &pInfo->pTDIX,
  918. 0xffffffff, //ULONG_MAX,
  919. &pInfo->TDIXcEntries );
  920. dbgprintf( (0,IDS_LSAENUMERATETRUSTEDDOMAINSEX_D,GetName(pInfo),Status,pInfo->TDIXcEntries) );
  921. if(Status==STATUS_NO_MORE_ENTRIES && pInfo->pTDIX==NULL) {
  922. pInfo->TDIXcEntries=0L;
  923. Status=STATUS_SUCCESS; //that means "0 entries"
  924. }
  925. return( Status );
  926. }
  927. //Enumerate NT4 Inbound trusts:
  928. netstatus = NetUserEnum( MakeSrvName(pInfo->DCName),
  929. 1,
  930. FILTER_INTERDOMAIN_TRUST_ACCOUNT,
  931. (LPBYTE*)(&pInfo->pUI1),
  932. 0xffffffff, //ULONG_MAX
  933. &UIRead,
  934. &UITotal,
  935. &reshandle
  936. );
  937. dbgprintf( (0,IDS_NETUSERENUM_D,GetName(pInfo),netstatus,UIRead) );
  938. if(netstatus!=NERR_Success) {
  939. Status = STATUS_UNSUCCESSFUL;
  940. goto cleanup;
  941. }
  942. pInfo->UI1cEntries=UIRead;
  943. //Enumerate NT4 Outbound trusts:
  944. { PLSA_TRUST_INFORMATION pTIShot=NULL;
  945. ULONG nShotsize=0;
  946. struct LsaTIshot *pTIsav=NULL;
  947. do {
  948. Status=LsaEnumerateTrustedDomains( pInfo->Policy,
  949. &EnumerationContext,
  950. &pTIShot,
  951. 0xffffffff, //ULONG_MAX,
  952. &nShotsize);
  953. dbgprintf( (0,IDS_LSAENUMERATETRUSTEDDOMAINS_D,GetName(pInfo),Status,nShotsize) );
  954. if( (Status != STATUS_SUCCESS) &&
  955. (Status != STATUS_MORE_ENTRIES) &&
  956. (Status != STATUS_NO_MORE_ENTRIES)
  957. ) {
  958. SetLastError( LsaNtStatusToWinError(Status) );
  959. goto cleanup;
  960. }
  961. if(pTIShot!=NULL) {
  962. if((pInfo->pTIs=realloc(pTIsav=pInfo->pTIs,pInfo->nTIs+1))==NULL) {
  963. free(pTIsav);
  964. Status = ERROR_NOT_ENOUGH_MEMORY;
  965. goto cleanup;
  966. }
  967. pInfo->TIcEntries+=nShotsize;
  968. pInfo->pTIs[pInfo->nTIs].count=nShotsize;
  969. pInfo->pTIs[pInfo->nTIs].pTI=pTIShot;
  970. pInfo->nTIs++;
  971. }
  972. } while (Status != STATUS_NO_MORE_ENTRIES);
  973. if(Dbg) printf("Total number of entries: %u\n",pInfo->TIcEntries);
  974. dbgprintf( (0,IDS_LSAENUMERATETRUSTEDDOMAINS_D,GetName(pInfo),Status,pInfo->TIcEntries) );
  975. if(Status==STATUS_NO_MORE_ENTRIES)
  976. Status=STATUS_SUCCESS;
  977. if(pInfo->pTIs==NULL) {
  978. pInfo->TIcEntries=0L;
  979. }
  980. }
  981. cleanup:
  982. return( Status );
  983. }
  984. struct bidir_st {
  985. ULONG index; // index in the 'Inbound' vector
  986. char type; // 'O' - Outbound, 'B' - Bidirectional
  987. };
  988. int __cdecl cmpbidir(const struct bidir_st *pb1, const struct bidir_st *pb2)
  989. {
  990. if(pb1->index==pb2->index)
  991. return(0);
  992. if(pb1->index>pb2->index)
  993. return(1);
  994. return(-1);
  995. }
  996. NTSTATUS
  997. PrintTrustLinks(
  998. IN PTD_DOM_INFO Info
  999. )
  1000. /*++
  1001. Print Trust Links
  1002. --*/
  1003. {
  1004. ULONG i,j;
  1005. if(Info->majver>=5) {
  1006. for(i=0; i<Info->TDIXcEntries; i++) {
  1007. char c;
  1008. switch(Info->pTDIX[i].TrustDirection)
  1009. {
  1010. case TRUST_DIRECTION_DISABLED: c='D'; break;
  1011. case TRUST_DIRECTION_INBOUND: c='I'; break;
  1012. case TRUST_DIRECTION_OUTBOUND: c='O'; break;
  1013. case TRUST_DIRECTION_BIDIRECTIONAL: c='B'; break;
  1014. default: c='-'; break;
  1015. }
  1016. printf("%-32wZ,%c",&Info->pTDIX[i].Name,c);
  1017. switch(Info->pTDIX[i].TrustType&0x000FFFFF)
  1018. {
  1019. case TRUST_TYPE_DOWNLEVEL:
  1020. printf(",T_downlevel"); break;
  1021. case TRUST_TYPE_UPLEVEL:
  1022. printf(",T_uplevel"); break;
  1023. case TRUST_TYPE_MIT:
  1024. printf(",T_mit"); break;
  1025. case TRUST_TYPE_DCE:
  1026. printf(",T_DCE"); break;
  1027. default:
  1028. printf("-"); break;
  1029. }
  1030. if(Info->pTDIX[i].TrustAttributes & TRUST_ATTRIBUTE_NON_TRANSITIVE)
  1031. printf(",A_NonTran");
  1032. else printf(",_");
  1033. if(Info->pTDIX[i].TrustAttributes & TRUST_ATTRIBUTE_UPLEVEL_ONLY )
  1034. printf(",A_UpLevelOnly");
  1035. else printf(",_");
  1036. if(Info->pTDIX[i].TrustAttributes & TRUST_ATTRIBUTE_FILTER_SIDS )
  1037. printf(",A_FilterSids");
  1038. else printf(",_");
  1039. if(Info->pTDIX[i].TrustAttributes & TRUST_ATTRIBUTE_FOREST_TRANSITIVE)
  1040. printf(",A_ForestTrust");
  1041. else printf(",_");
  1042. if(SidList) {
  1043. printf(",");
  1044. PrintSID(Info->pTDIX[i].Sid);
  1045. }
  1046. printf("\n");
  1047. }
  1048. }
  1049. else {
  1050. //Info->majver<=4
  1051. int shot;
  1052. struct bidir_st *p=NULL, *q=NULL;
  1053. if((p=calloc(Info->TIcEntries,sizeof(struct bidir_st)))==NULL)
  1054. return(ERROR_NOT_ENOUGH_MEMORY);
  1055. //for(q=p,i=0; i<Info->TIcEntries; q++,i++) {
  1056. for(q=p,shot=0; shot<Info->nTIs; shot++) {
  1057. for(i=0; i<Info->pTIs[shot].count; i++,q++) {
  1058. WCHAR buf[1024];
  1059. swprintf(buf,L"%wZ",&Info->pTIs[shot].pTI[i].Name);
  1060. for(j=0; j<Info->UI1cEntries; j++)
  1061. if(wcscmp(buf,CutDlrFromName(Info->pUI1[j].usri1_name))==0)
  1062. break;
  1063. if((q->index=j)<Info->UI1cEntries) //found...
  1064. q->type='B'; //actually it's a Bidir link...
  1065. else q->type='O'; //or this is a "true" Outbound...
  1066. }
  1067. }
  1068. //print Outbound and Bidirectional links
  1069. //for(q=p,i=0; i<Info->TIcEntries; q++,i++)
  1070. for(q=p,shot=0; shot<Info->nTIs; shot++)
  1071. for(i=0; i<Info->pTIs[shot].count; i++,q++)
  1072. printf("%-32wZ,%c,T_downlevel,_,_,_,_\n",&Info->pTIs[shot].pTI[i].Name,q->type);
  1073. qsort(p,Info->TIcEntries,sizeof(struct bidir_st),cmpbidir);
  1074. //print Inbound links
  1075. for(q=p,j=i=0; i<Info->UI1cEntries; i++) {
  1076. if(j<Info->TIcEntries && q->index==i) { //if it was a Bidirectional, it was already printed...
  1077. j++; q++;
  1078. continue;
  1079. }
  1080. printf("%-32ws,I,T_downlevel,_,_,_,_\n",CutDlrFromName(Info->pUI1[i].usri1_name));
  1081. }
  1082. if(p!=NULL)
  1083. free(p);
  1084. }
  1085. return( STATUS_SUCCESS );
  1086. }
  1087. NTSTATUS
  1088. CreateNT5TrustDomObject(
  1089. IN PTD_DOM_INFO Local,
  1090. IN PTD_DOM_INFO Remote,
  1091. IN PWSTR Password,
  1092. IN BOOLEAN Downlevel,
  1093. IN BOOLEAN Mit,
  1094. IN ULONG Direction
  1095. )
  1096. /*++
  1097. Routine Description:
  1098. Creates the trusted domain object on an NT5 domain (DS based)
  1099. Arguments:
  1100. Local -- Information about the domain doing the trust
  1101. Remote -- Information about the domain being trusted
  1102. Password -- Password to set on the trust
  1103. Downlevel -- If TRUE, create this as a downlevel trust
  1104. Mit -- If TRUE, creates this as an Mit style trust
  1105. Direction -- Which direction to make the link in.
  1106. Return Value:
  1107. STATUS_SUCCESS -- Success
  1108. --*/
  1109. {
  1110. NTSTATUS Status = STATUS_SUCCESS;
  1111. WCHAR Domain[1024]={L'\0'};
  1112. WCHAR DnsDomain[1024]={L'\0'};
  1113. TRUSTED_DOMAIN_INFORMATION_EX TDIEx;
  1114. LSA_AUTH_INFORMATION AuthData;
  1115. TRUSTED_DOMAIN_AUTH_INFORMATION AuthInfoEx;
  1116. PSID Sid = NULL;
  1117. swprintf(Domain,L"%wZ",GetFlatName(Remote));
  1118. swprintf(DnsDomain,L"%wZ",GetName(Remote));
  1119. Status = NtQuerySystemTime( &AuthData.LastUpdateTime );
  1120. if ( !NT_SUCCESS( Status ) ) {
  1121. return( Status );
  1122. }
  1123. AuthData.AuthType = TRUST_AUTH_TYPE_CLEAR;
  1124. AuthData.AuthInfoLength = wcslen( Password ) * sizeof( WCHAR );
  1125. AuthData.AuthInfo = (PUCHAR)Password;
  1126. RtlZeroMemory( &AuthInfoEx, sizeof( LSA_AUTH_INFORMATION ) );
  1127. if ( Direction & TRUST_DIRECTION_INBOUND ) {
  1128. AuthInfoEx.IncomingAuthInfos = 1;
  1129. AuthInfoEx.IncomingAuthenticationInformation = &AuthData;
  1130. AuthInfoEx.IncomingPreviousAuthenticationInformation = NULL;
  1131. }
  1132. if ( Direction & TRUST_DIRECTION_OUTBOUND ) {
  1133. AuthInfoEx.OutgoingAuthInfos = 1;
  1134. AuthInfoEx.OutgoingAuthenticationInformation = &AuthData;
  1135. AuthInfoEx.OutgoingPreviousAuthenticationInformation = NULL;
  1136. }
  1137. if (!Mit)
  1138. {
  1139. RtlCopyMemory( &TDIEx.Name, GetName(Remote), sizeof( UNICODE_STRING ) );
  1140. RtlCopyMemory( &TDIEx.FlatName, GetFlatName(Remote), sizeof( UNICODE_STRING ) );
  1141. switch(Remote->DomInfoType) {
  1142. case DNS: TDIEx.Sid = Remote->u.DnsDomainInfo->Sid;
  1143. break;
  1144. case Primary: TDIEx.Sid = Remote->u.PrimaryDomainInfo->Sid;
  1145. break;
  1146. default: Status = GenerateRandomSID( &Sid);
  1147. if (!NT_SUCCESS(Status))
  1148. {
  1149. return(Status);
  1150. }
  1151. TDIEx.Sid = Sid;
  1152. break;
  1153. }
  1154. //TDIEx.Sid = (Remote->DomInfoType==DNS?Remote->u.DnsDomainInfo->Sid:Remote->u.PrimaryDomainInfo->Sid);
  1155. }
  1156. else
  1157. {
  1158. // printf("****Set %ws for the Name and FlatName in the trust object... GetFlatName(Local)=%wZ\n",
  1159. // Domain,GetFlatName(Local));
  1160. RtlInitUnicodeString(
  1161. &TDIEx.Name,
  1162. Domain
  1163. );
  1164. RtlInitUnicodeString(
  1165. &TDIEx.FlatName,
  1166. Domain
  1167. );
  1168. Status = GenerateRandomSID( &Sid);
  1169. if (!NT_SUCCESS(Status))
  1170. {
  1171. return(Status);
  1172. }
  1173. TDIEx.Sid = Sid;
  1174. }
  1175. TDIEx.TrustDirection = Direction;
  1176. TDIEx.TrustType = Mit ? TRUST_TYPE_MIT : (Downlevel ? TRUST_TYPE_DOWNLEVEL : TRUST_TYPE_UPLEVEL);
  1177. TDIEx.TrustAttributes = 0;
  1178. Status = LsaCreateTrustedDomainEx( Local->Policy,
  1179. &TDIEx,
  1180. &AuthInfoEx,
  1181. TRUSTED_ALL_ACCESS,
  1182. &Local->TrustedDomain );
  1183. if (!NT_SUCCESS(Status)) {
  1184. dbgprintf( (0,IDS_LSACREATETRUSTEDDOMAINEX_F, GetName(Local), DnsDomain, Status) );
  1185. if(Status==STATUS_OBJECT_NAME_COLLISION)
  1186. dbgprintf( (0,IDS_STATUS_OBJECT_NAME_COLLISION, GetName(Local), DnsDomain) );
  1187. }
  1188. else LsaClose(Local->TrustedDomain); //not interested in the actual handle...
  1189. if (Sid != NULL)
  1190. {
  1191. RtlFreeSid(Sid);
  1192. }
  1193. return( Status );
  1194. }
  1195. NTSTATUS
  1196. CreateTrustLink(
  1197. IN PTD_DOM_INFO pInfoA,
  1198. IN PTD_DOM_INFO pInfoB,
  1199. IN PWSTR Password,
  1200. IN BOOLEAN Downlevel,
  1201. IN BOOLEAN Mit,
  1202. IN BOOLEAN ParentChild,
  1203. IN ULONG Direction
  1204. )
  1205. {
  1206. NET_API_STATUS netstatus=NERR_Success;
  1207. NTSTATUS Status = STATUS_SUCCESS;
  1208. PWSTR pDomain=NULL;
  1209. if( !Force // if -force was NOT specified...
  1210. &&
  1211. !Mit // for a non-MIT trust...
  1212. &&
  1213. (pInfoA->DomInfoType==Minimal || pInfoB->DomInfoType==Minimal)
  1214. // creating links not supported in 'Minimal' mode...
  1215. )
  1216. return( STATUS_UNSUCCESSFUL );
  1217. if(pInfoA->majver>=5) {
  1218. Status = CreateNT5TrustDomObject(
  1219. pInfoA,
  1220. pInfoB,
  1221. Password,
  1222. Downlevel,Mit,Direction
  1223. );
  1224. return( Status );
  1225. }
  1226. ////////////////////////////////////////////////////////////////////////
  1227. //for a NT4 domain...
  1228. if(Mit || ParentChild)
  1229. return (STATUS_INVALID_PARAMETER);
  1230. if(Direction & TRUST_DIRECTION_INBOUND) {
  1231. USER_INFO_1 UI1;
  1232. DWORD dwParmErr=0xffffffff;
  1233. memset(&UI1,0,sizeof(UI1));
  1234. pDomain=AddDlrToDomainName(pInfoB);
  1235. // Create the necessary SAM account.
  1236. UI1.usri1_name = pDomain;
  1237. UI1.usri1_password = Password;
  1238. UI1.usri1_password_age = 0;
  1239. UI1.usri1_priv = USER_PRIV_USER;
  1240. UI1.usri1_home_dir = NULL;
  1241. UI1.usri1_comment = NULL;
  1242. UI1.usri1_flags = UF_INTERDOMAIN_TRUST_ACCOUNT | UF_SCRIPT;
  1243. UI1.usri1_script_path = NULL;
  1244. netstatus = NetUserAdd(
  1245. MakeSrvName(pInfoA->DCName),
  1246. 1,
  1247. (LPBYTE)&UI1,
  1248. &dwParmErr
  1249. );
  1250. if(netstatus != NERR_Success) {
  1251. resprintf(0,IDS_NETUSERADD_F,pInfoA->DCName,pDomain,netstatus);
  1252. if(netstatus==NERR_UserExists)
  1253. resprintf(0,IDS_NERR_UserExists,pInfoA->DCName,pDomain);
  1254. goto Done;
  1255. }
  1256. }
  1257. if(Direction & TRUST_DIRECTION_OUTBOUND) {
  1258. LSA_TRUST_INFORMATION TI;
  1259. PUNICODE_STRING puSecret;
  1260. UNICODE_STRING uPass;
  1261. LSA_HANDLE hSecret;
  1262. swprintf(Domain,L"%wZ",GetFlatName(pInfoB));
  1263. RtlInitUnicodeString(&TI.Name,Domain);
  1264. { PSID Sid = NULL;
  1265. switch(pInfoB->DomInfoType) {
  1266. case DNS: TI.Sid = pInfoB->u.DnsDomainInfo->Sid;
  1267. break;
  1268. case Primary: TI.Sid = pInfoB->u.PrimaryDomainInfo->Sid;
  1269. break;
  1270. default: Status = GenerateRandomSID( &Sid);
  1271. if (!NT_SUCCESS(Status))
  1272. {
  1273. return(Status);
  1274. }
  1275. TI.Sid = Sid;
  1276. break;
  1277. }
  1278. }
  1279. //TI.Sid=(pInfoB->DomInfoType==DNS?pInfoB->u.DnsDomainInfo->Sid:pInfoB->u.PrimaryDomainInfo->Sid);
  1280. Status = LsaCreateTrustedDomain(
  1281. pInfoA->Policy,
  1282. &TI,
  1283. TRUSTED_ALL_ACCESS,
  1284. &pInfoA->TrustedDomain
  1285. );
  1286. if( !NT_SUCCESS(Status)) {
  1287. resprintf(0,IDS_LSACREATETRUSTEDDOMAIN_F,Status);
  1288. goto Done;
  1289. }
  1290. else LsaClose(pInfoA->TrustedDomain); //not interested in the actual handle...
  1291. puSecret=MakeSecretName(pInfoB);
  1292. Status = LsaCreateSecret(
  1293. pInfoA->Policy,
  1294. puSecret,
  1295. SECRET_ALL_ACCESS,
  1296. &hSecret
  1297. );
  1298. if(!NT_SUCCESS(Status)) {
  1299. resprintf(0,IDS_LSACREATESECRET_F,Status);
  1300. goto Done;
  1301. }
  1302. RtlInitUnicodeString(&uPass,Password);
  1303. Status=LsaSetSecret(
  1304. hSecret,
  1305. &uPass,
  1306. NULL
  1307. );
  1308. if(!NT_SUCCESS(Status)) {
  1309. resprintf(0,IDS_LSASETSECRET_F,Status);
  1310. LsaDelete(hSecret); hSecret=NULL;
  1311. goto Done;
  1312. }
  1313. if(hSecret!=NULL)
  1314. LsaClose(hSecret);
  1315. }
  1316. Done:
  1317. // if(pInfoA->TrustedDomain!=NULL)
  1318. // LsaClose(pInfoA->TrustedDomain);
  1319. return(Status);
  1320. }
  1321. NTSTATUS
  1322. DeleteTrustLink(
  1323. IN PTD_DOM_INFO pInfoA,
  1324. IN PTD_DOM_INFO pInfoB
  1325. )
  1326. /*++
  1327. Routine Description:
  1328. Deletes on A trusted domain things related to a trust to B
  1329. Return Value:
  1330. STATUS_SUCCESS -- Success
  1331. --*/
  1332. {
  1333. NET_API_STATUS netstatus=NERR_Success;
  1334. NTSTATUS Status=STATUS_SUCCESS;
  1335. //#define NO_TRUST_OBJECTS 1
  1336. //#define NO_SECRETS 2
  1337. //#define NO_TRUST_ACCOUNTS 4
  1338. // DWORD dwFlag=0;
  1339. ULONG i, ix=0;
  1340. PSID sid=NULL;
  1341. PTRUSTED_DOMAIN_INFORMATION_EX pTDIx = NULL;
  1342. PLSA_UNICODE_STRING puDomBName=GetName(pInfoB);
  1343. PLSA_UNICODE_STRING puDomBFlatName=GetFlatName(pInfoB);
  1344. PLSA_UNICODE_STRING puSecret;
  1345. dbgprintf( (0,IDS_DELTRUSTFROMTO,GetName(pInfoA),puDomBName) );
  1346. Status = GetTrustLinks(pInfoA);
  1347. if(!NT_SUCCESS(Status)) {
  1348. resprintf(0,IDS_GETTRUSTLINKS_F,GetName(pInfoA),Status);
  1349. return(Status);
  1350. }
  1351. //try to find a trust link to B...
  1352. if(pInfoA->majver>=5) {
  1353. // now try to get a LSA_HANDLE to a (possible) trust object with this domain...
  1354. // if not found any, that Info->TrustedDomain will remain NULL
  1355. Status = LsaQueryTrustedDomainInfoByName(
  1356. pInfoA->Policy,
  1357. puDomBName, //IN PLSA_UNICODE_STRING TrustedDomainName
  1358. TrustedDomainInformationEx, //IN TRUSTED_INFORMATION_CLASS InformationClass,
  1359. &pTDIx //OUT PVOID *Buffer
  1360. );
  1361. if ( !NT_SUCCESS( Status ) ) {
  1362. if(Status==STATUS_OBJECT_NAME_NOT_FOUND) {
  1363. pInfoA->TrustedDomain=NULL;
  1364. dbgprintf( (0,IDS_NO_TRUST_OBJECT_D,GetName(pInfoA),puDomBName) );
  1365. Status=STATUS_SUCCESS;
  1366. }
  1367. else resprintf(0,IDS_LSAQUERYTRUSTEDDOMAININFOBYNAME_F,GetName(pInfoA),puDomBName,Status);
  1368. goto cleanup;
  1369. }
  1370. if(pTDIx->Sid==NULL)
  1371. dbgprintf( (0,IDS_LSAQUERYNULLSID) ); //"NULL sid returned by LsaQueryTrustedDomainInfoByName\n"
  1372. sid=pTDIx->Sid;
  1373. //check to see if the trusted domain object can be opened with that sid...
  1374. if(sid!=NULL) {
  1375. LSA_HANDLE td;
  1376. Status=LsaOpenTrustedDomain(pInfoA->Policy,
  1377. sid,TRUSTED_ALL_ACCESS,&td);
  1378. if(NT_SUCCESS( Status )) // if it was ok...
  1379. LsaClose(td); // ...just close the handle (leave the following code to open it again later)
  1380. else { // if failed...
  1381. if(Status==STATUS_INVALID_PARAMETER && Force) {
  1382. printf("LsaOpenTrustedDomain for the trust to %wZ failed with STATUS_INVALID_PARAMETER (i.e. the sid is bad)\n"
  1383. "Trying to set a valid sid...\n",puDomBName);
  1384. // if was STATUS_INVALID_PARAMETER (i.e. the sid) and '-overwritesid' option used...
  1385. RtlFreeSid(sid); // free the old sid
  1386. sid=NULL; // make it NULL as a signal to the next 'if' (see below) to
  1387. } // pick it up and set a new random valid sid in its place
  1388. }
  1389. }
  1390. if(sid==NULL) {
  1391. // try to put a sid THERE ...
  1392. Status = GenerateRandomSID ( &pTDIx->Sid );
  1393. if (!NT_SUCCESS( Status ))
  1394. goto cleanup;
  1395. Status = LsaSetTrustedDomainInfoByName(
  1396. pInfoA->Policy,
  1397. puDomBName, //IN PLSA_UNICODE_STRING TrustedDomainName
  1398. TrustedDomainInformationEx, //IN TRUSTED_INFORMATION_CLASS InformationClass,
  1399. pTDIx //IN PVOID Buffer
  1400. );
  1401. if(!NT_SUCCESS( Status )) {
  1402. resprintf(0,IDS_LSASETTRUSTEDDOMAININFOBYNAME_F,GetName(pInfoA),puDomBName,Status);
  1403. goto cleanup;
  1404. }
  1405. sid=pTDIx->Sid;
  1406. if(sid==NULL)
  1407. resprintf(0,IDS_LSASETNULLSID); //"LsaSetTrustedDomainInfoByName: NULL sid\n"
  1408. }
  1409. }
  1410. else { // pInfoA->majver<=4
  1411. //check for Outbound....
  1412. int shot;
  1413. //for(ix=0; ix<pInfoA->TIcEntries; ix++)
  1414. for(shot=0; shot<pInfoA->nTIs; shot++)
  1415. for(ix=0; ix<pInfoA->pTIs[shot].count; ix++)
  1416. if(RtlEqualUnicodeString(&pInfoA->pTIs[shot].pTI[ix].Name,puDomBFlatName,TRUE))
  1417. //it was FALSE, i.e. case sensitive
  1418. goto out_of_loop;
  1419. out_of_loop:
  1420. if(ix<pInfoA->TIcEntries)
  1421. sid=pInfoA->pTIs[shot].pTI[ix].Sid;
  1422. else {
  1423. printf("No OUTBOUND trust to %wZ found...\n",puDomBFlatName);
  1424. }
  1425. }
  1426. if(sid==NULL)
  1427. dbgprintf( (0,IDS_NULLSID) ); //"#### NULL sid\n"
  1428. if(sid!=NULL) {
  1429. Status=LsaOpenTrustedDomain(
  1430. pInfoA->Policy,
  1431. sid,
  1432. TRUSTED_ALL_ACCESS,
  1433. &pInfoA->TrustedDomain
  1434. );
  1435. //printf("Handle=0x%08lx (Status: 0x%08lx)\n",pInfoA->TrustedDomain,Status);
  1436. if(!NT_SUCCESS(Status)) {
  1437. resprintf(0,IDS_LSAOPENTRUSTEDDOMAIN_F,Status);
  1438. //return(Status);
  1439. }
  1440. dbgprintf( (0,IDS_LSATRUSTHANDLE,pInfoA->TrustedDomain,Status) );
  1441. }
  1442. else {
  1443. if( //pInfoA->majver<=4 &&
  1444. ix<pInfoA->TIcEntries) {
  1445. resprintf(0,IDS_NONNULL_SID,puDomBName);
  1446. Status=STATUS_INVALID_SID;
  1447. }
  1448. else //simply no trust objects...
  1449. Status=STATUS_SUCCESS;
  1450. }
  1451. if(pInfoA->TrustedDomain) {
  1452. dbgprintf( (0,IDS_LSADELOBJ,pInfoA->TrustedDomain) );
  1453. Status = LsaDelete( pInfoA->TrustedDomain );
  1454. }
  1455. if (!NT_SUCCESS(Status))
  1456. dbgprintf( (0,IDS_DELETION_F,GetName(pInfoA), Status) );
  1457. //NT4 only section...
  1458. if(pInfoA->majver<=4) {
  1459. LSA_HANDLE hSecret;
  1460. //delete secret thing...
  1461. puSecret=MakeSecretName(pInfoB);
  1462. Status = LsaOpenSecret(
  1463. pInfoA->Policy,
  1464. puSecret,
  1465. SECRET_ALL_ACCESS,
  1466. &hSecret
  1467. );
  1468. if(Status==STATUS_OBJECT_NAME_NOT_FOUND) {
  1469. dbgprintf( (0,IDS_SECRET_NOT_FOUND_D,puSecret) );
  1470. Status=STATUS_SUCCESS;
  1471. }
  1472. else {
  1473. if(!NT_SUCCESS(Status)) {
  1474. resprintf(0,IDS_LSAOPENSECRET_F,Status);
  1475. }
  1476. else {
  1477. Status = LsaDelete(hSecret); hSecret=NULL;
  1478. if(!NT_SUCCESS(Status))
  1479. resprintf(0,IDS_LSADELETE_F,puSecret,Status);
  1480. }
  1481. }
  1482. //delete Interdomain Trust Account....
  1483. netstatus = NetUserDel(
  1484. MakeSrvName(pInfoA->DCName),
  1485. AddDlrToDomainName(pInfoB)
  1486. );
  1487. if(netstatus!=NERR_Success && netstatus!=NERR_UserNotFound) {
  1488. resprintf(0,IDS_NETUSERDEL_F,AddDlrToDomainName(pInfoB),netstatus);
  1489. Status=STATUS_UNSUCCESSFUL;
  1490. }
  1491. }
  1492. cleanup:
  1493. if(pTDIx!=NULL)
  1494. LsaFreeMemory(pTDIx);
  1495. if(sid!=NULL)
  1496. RtlFreeSid(sid);
  1497. return( Status );
  1498. }
  1499. NTSTATUS
  1500. CheckTrustLink(
  1501. IN PTD_DOM_INFO pInfoA,
  1502. IN PTD_DOM_INFO pInfoB
  1503. )
  1504. /*++
  1505. Routine Description:
  1506. Checks on A trusted domain sids related to a trust to B
  1507. Return Value:
  1508. STATUS_SUCCESS -- Success
  1509. --*/
  1510. {
  1511. NET_API_STATUS netstatus=NERR_Success;
  1512. NTSTATUS Status=STATUS_SUCCESS;
  1513. PSID sid=NULL, sidb=NULL;
  1514. BOOL UnknownRemoteSid=FALSE;
  1515. PTRUSTED_DOMAIN_INFORMATION_EX pTDIx = NULL;
  1516. PLSA_UNICODE_STRING puDomBName=GetName(pInfoB);
  1517. PLSA_UNICODE_STRING puDomBFlatName=GetFlatName(pInfoB);
  1518. dbgprintf( (0,IDS_CHKTRUSTFROMTO,GetName(pInfoA),puDomBName) );
  1519. //try to find a trust link to B...
  1520. if(pInfoA->majver>=5) {
  1521. // now try to get a LSA_HANDLE to a (possible) trust object with this domain...
  1522. // if not found any, that Info->TrustedDomain will remain NULL
  1523. Status = LsaQueryTrustedDomainInfoByName(
  1524. pInfoA->Policy,
  1525. puDomBName, //IN PLSA_UNICODE_STRING TrustedDomainName
  1526. TrustedDomainInformationEx, //IN TRUSTED_INFORMATION_CLASS InformationClass,
  1527. &pTDIx //OUT PVOID *Buffer
  1528. );
  1529. if ( !NT_SUCCESS( Status ) ) {
  1530. if(Status==STATUS_OBJECT_NAME_NOT_FOUND) {
  1531. pInfoA->TrustedDomain=NULL;
  1532. dbgprintf( (0,IDS_NO_TRUST_OBJECT_D,GetName(pInfoA),puDomBName) );
  1533. Status=STATUS_SUCCESS;
  1534. }
  1535. else resprintf(0,IDS_LSAQUERYTRUSTEDDOMAININFOBYNAME_F,GetName(pInfoA),puDomBName,Status);
  1536. goto cleanup;
  1537. }
  1538. sid=pTDIx->Sid;
  1539. }
  1540. else { // pInfoA->majver<=4
  1541. //check for Outbound....
  1542. int shot;
  1543. ULONG i;
  1544. for(shot=0; shot<pInfoA->nTIs; shot++)
  1545. for(i=0; i<pInfoA->pTIs[shot].count; i++)
  1546. if(RtlEqualUnicodeString(&pInfoA->pTIs[shot].pTI[i].Name,puDomBFlatName,TRUE))
  1547. //it was FALSE, i.e. case sensitive
  1548. goto out_of_loop;
  1549. out_of_loop:
  1550. if(i<pInfoA->TIcEntries)
  1551. sid=pInfoA->pTIs[shot].pTI[i].Sid;
  1552. }
  1553. switch(pInfoB->DomInfoType) {
  1554. case DNS: sidb = pInfoB->u.DnsDomainInfo->Sid;
  1555. break;
  1556. case Primary: sidb = pInfoB->u.PrimaryDomainInfo->Sid;
  1557. break;
  1558. default: sidb=NULL;
  1559. UnknownRemoteSid=TRUE;
  1560. break;
  1561. }
  1562. //now sid contains the Sid of the trust object, if any... (on NT4, only the OUTBOUND
  1563. //end of the trust has a trust object...)
  1564. //Print them and compare them...
  1565. printf("TDO on %wZ: sid:\t",GetName(pInfoA));
  1566. PrintSID(sid);
  1567. printf("\n");
  1568. if(UnknownRemoteSid) {
  1569. if(pInfoB->majver<=4)
  1570. printf("Domain %wZ does not have a trust object (possibly an NT4 only with an INBOUND trust)\n",puDomBName);
  1571. else
  1572. printf("Sid for domain %wZ is unknown (possible localonly used or error getting Dns/Primary DomainInfo)",puDomBName);
  1573. }
  1574. else {
  1575. if(sid!=NULL && IsValidSid(sid) && sidb!=NULL && IsValidSid(sidb)) {
  1576. if(EqualSid(sid,sidb))
  1577. printf("Sid on %wZ is the same:\t",puDomBName);
  1578. else printf("Sid on %wZ is different:\t",puDomBName);
  1579. }
  1580. else {
  1581. printf("Sid on %wZ: ",puDomBName);
  1582. }
  1583. PrintSID(sidb);
  1584. }
  1585. printf("\n");
  1586. cleanup:
  1587. if(pTDIx!=NULL)
  1588. LsaFreeMemory(pTDIx);
  1589. return( Status );
  1590. }
  1591. void ParseForDCName(WCHAR DomBuf[], WCHAR DCBuf[])
  1592. {
  1593. WCHAR *pw;
  1594. DCBuf[0]=L'\0';
  1595. wcstok(DomBuf,L":");
  1596. if((pw=wcstok(NULL,L":"))!=NULL)
  1597. wcscpy(DCBuf,pw);
  1598. if(DomBuf[0]==L'*' || wcscmp(DomBuf,L"(local)")==0)
  1599. DomBuf[0]=L'\0';
  1600. }
  1601. //the NameValidate stuff below taken from icanon.h
  1602. NET_API_STATUS
  1603. NET_API_FUNCTION
  1604. I_NetNameValidate(
  1605. IN LPWSTR ServerName OPTIONAL,
  1606. IN LPWSTR Name,
  1607. IN DWORD NameType,
  1608. IN DWORD Flags );
  1609. //NameType:
  1610. #define NAMETYPE_DOMAIN 6
  1611. //Flags:
  1612. //#define LM2X_COMPATIBLE 0x80000000L
  1613. #ifdef COMMENT
  1614. #define CTRL_CHARS_0 L"\001\002\003\004\005\006\007"
  1615. #define CTRL_CHARS_1 L"\010\011\012\013\014\015\016\017"
  1616. #define CTRL_CHARS_2 L"\020\021\022\023\024\025\026\027"
  1617. #define CTRL_CHARS_3 L"\030\031\032\033\034\035\036\037"
  1618. #define CTRL_CHARS_STR CTRL_CHARS_0 CTRL_CHARS_1 CTRL_CHARS_2 CTRL_CHARS_3
  1619. #define ILLEGAL_DOMAIN_CHARS_STR
  1620. #define ILLEGAL_DOMAIN_NAME_CHARS_STR L"\"/\\[]:|<>+;,?" CTRL_CHARS_STR L"*" L" "
  1621. #endif //COMMENT
  1622. BOOL ValidateDomain(WCHAR DomBuf[])
  1623. { WCHAR Buf[MAX_PATH + 1]= { L'\0' };
  1624. WCHAR *p;
  1625. int DomBuf_len, oem_name_len;
  1626. NET_API_STATUS netstatus=NERR_Success;
  1627. if(DomBuf==NULL || DomBuf[0]==L'\0')
  1628. return(TRUE);
  1629. wcscpy(Buf,DomBuf);
  1630. //for DNS name, test each component; for a flat name, there's already only one...
  1631. for(p=wcstok(Buf,L"."); p!=NULL; p=wcstok(NULL,L"."))
  1632. if((netstatus=I_NetNameValidate(NULL,p,NAMETYPE_DOMAIN,0))!=NERR_Success)
  1633. return(FALSE);
  1634. return(TRUE);
  1635. #ifdef COMMENT
  1636. DomBuf_len=wcslen(DomBuf);
  1637. // oem_name_len : length in bytes in oem character set
  1638. // name_len : ifdef UNICODE
  1639. // character length in unicode
  1640. // else
  1641. // length in bytes in oem character set
  1642. //
  1643. {
  1644. BOOL fUsedDefault;
  1645. oem_name_len = WideCharToMultiByte(
  1646. CP_OEMCP, // UINT CodePage
  1647. 0, // DWORD dwFlags
  1648. DomBuf, // LPWSTR lpWideChar
  1649. DomBuf_len, // int cchWideChar
  1650. NULL, // LPSTR lpMultiByteStr
  1651. 0, // int cchMultiByte
  1652. NULL, // use system default char
  1653. &fUsedDefault); //
  1654. }
  1655. if(oem_name_len<1 || oem_name_len>=DNLEN)
  1656. return(FALSE);
  1657. if(wcscspn(DomBuf,ILLEGAL_DOMAIN_NAME_CHARS_STR) < DomBuf_len)
  1658. return(FALSE);
  1659. return(TRUE);
  1660. #endif //COMMENT
  1661. }
  1662. #define ARG_CASE_S 0x8000 // case sensitive argument
  1663. #define BOOL_ARG(argvec,a_index,var) {if((argvec)[(a_index)].b) (var)=(BOOLEAN)((argvec)[(a_index)].b);}
  1664. enum e_arg_type { ARG_S, ARG_U, ARG_B, ARG_I, ARG_L, ARG_UD };
  1665. struct _arg_st {
  1666. char *name;
  1667. union {
  1668. char *s;
  1669. ULONG u;
  1670. BOOL b;
  1671. int i;
  1672. long l;
  1673. void (*fct)(char *);
  1674. };
  1675. enum e_arg_type t;
  1676. };
  1677. #define NELEMS(a) (sizeof(a)/sizeof(a[0]))
  1678. int process_opt(int argc, char **argv, struct _arg_st arg[])
  1679. { // command line parameters processing
  1680. int i,j,k; char *p; struct _arg_st *pa;
  1681. int r=1;
  1682. // process options
  1683. for (i=1; i<argc; i++) {
  1684. if (argv[i][0]=='/' || argv[i][0]=='-') {
  1685. p=strtok(argv[i]+1,":");
  1686. for(j=0; arg[j].name!=NULL; j++) {
  1687. if(p!=NULL && ( ((arg[j].t & ARG_CASE_S) && strcmp(p,arg[j].name)==0) ||
  1688. _stricmp(p,arg[j].name)==0 ) )
  1689. break;
  1690. }
  1691. if(arg[j].name==NULL) {
  1692. resprintf(1,IDS_UNKNOWN_OPTION,p);
  1693. r=0;
  1694. continue;
  1695. }
  1696. switch(arg[j].t)
  1697. {
  1698. case ARG_B:
  1699. if( (p=strtok(NULL,""))==NULL
  1700. || _stricmp(p,"on")==0
  1701. || _stricmp(p,"true")==0)
  1702. arg[j].b=TRUE;
  1703. else arg[j].b=FALSE;
  1704. break;
  1705. case ARG_S:
  1706. if((p=strtok(NULL,""))!=NULL)
  1707. arg[j].s=_strdup(p);
  1708. else arg[j].s=NULL;
  1709. break;
  1710. case ARG_U:
  1711. if((p=strtok(NULL,""))!=NULL)
  1712. arg[j].u=(ULONG)atol(p);
  1713. break;
  1714. case ARG_L:
  1715. if((p=strtok(NULL,""))!=NULL)
  1716. arg[j].l=atol(p);
  1717. break;
  1718. case ARG_I:
  1719. if((p=strtok(NULL,""))!=NULL)
  1720. arg[j].i=atoi(p);
  1721. break;
  1722. case ARG_UD:
  1723. p=strtok(NULL,"");
  1724. (*arg[j].fct)(p);
  1725. break;
  1726. }
  1727. }
  1728. }
  1729. return(r);
  1730. }
  1731. // options
  1732. enum e_arg_idx { A_LIST, A_BOTH, A_IN, A_OUT,
  1733. A_UNTRUST, A_CHECK,
  1734. A_VERIFY,
  1735. A_LOCALONLY, A_DOWNLEVEL, A_MIT, A_PARENT,
  1736. A_DEBUG,
  1737. A_PW,
  1738. A_FORCE,
  1739. A_NT4,
  1740. A_SIDLIST,
  1741. A_LASTARG };
  1742. struct _arg_st opt_arg[]={
  1743. {"list", NULL, ARG_B}, // A_LIST
  1744. {"both", NULL, ARG_B}, // A_BOTH
  1745. {"in", NULL, ARG_B}, // A_IN
  1746. {"out", NULL, ARG_B}, // A_OUT
  1747. {"untrust", NULL, ARG_B}, // A_UNTRUST
  1748. {"sidcheck", NULL, ARG_B}, // A_CHECK
  1749. {"verify", NULL, ARG_B}, // A_VERIFY
  1750. {"localonly", NULL, ARG_B}, // A_LOCALONLY
  1751. {"downlevel", NULL, ARG_B}, // A_DOWNLEVEL
  1752. {"mit", NULL, ARG_B}, // A_MIT
  1753. {"parent", NULL, ARG_B}, // A_PARENT
  1754. {"debug", NULL, ARG_B}, // A_DEBUG
  1755. {"pw", NULL, ARG_S}, // A_PW
  1756. {"force", NULL, ARG_B}, // A_FORCE
  1757. {"nt4", NULL, ARG_B}, // A_NT4
  1758. {"sidlist", NULL, ARG_B}, // A_SIDLIST
  1759. {NULL, NULL}
  1760. };
  1761. INT
  1762. __cdecl main ( // it was _CRTAPI1
  1763. int argc,
  1764. char **argv)
  1765. {
  1766. NTSTATUS Status = STATUS_SUCCESS;
  1767. NTSTATUS StatusL = STATUS_SUCCESS;
  1768. NTSTATUS StatusR = STATUS_SUCCESS;
  1769. WCHAR ADomain[MAX_PATH + 1]= { L'\0' };
  1770. WCHAR BDomain[MAX_PATH + 1]= { L'\0' };
  1771. WCHAR ADC[MAX_PATH + 1]= { L'\0' };
  1772. WCHAR BDC[MAX_PATH + 1]= { L'\0' }; // BDC means just DC for machine B and NOT B(ackup) DC !!!...
  1773. WCHAR Xbuf[MAX_PATH + 1]= { L'\0' }; // general purpose buffer
  1774. WCHAR Ybuf[MAX_PATH + 1]= { L'\0' }; // general purpose buffer
  1775. INT i,j;
  1776. BOOLEAN List=FALSE;
  1777. BOOLEAN Both = FALSE, DirIn=FALSE, DirOut=FALSE;
  1778. BOOLEAN LocalOnly = FALSE, Untrust = FALSE, Downlevel = FALSE, Parent = FALSE;
  1779. BOOLEAN Check=FALSE;
  1780. BOOLEAN Mit = FALSE;
  1781. BOOLEAN LocalCreated = FALSE;
  1782. BOOL Verify = FALSE;
  1783. // BOOLEAN Force = FALSE; moved global
  1784. // BOOLEAN Nt4 = FALSE; this is global
  1785. // BOOLEAN Dbg = FALSE; this is global
  1786. DWORD DirectionLocal=0, DirectionRemote=0;
  1787. WCHAR PasswordBuff[1024];
  1788. PWSTR Password = NULL;
  1789. TD_DOM_INFO Local={0},
  1790. Remote={0};
  1791. LSA_UNICODE_STRING uDomNameL,uDomNameR;
  1792. // help requested? display it and exit ...
  1793. if ( argc<2 ||
  1794. _stricmp( argv[1], "-?") == 0 ||
  1795. _stricmp( argv[1], "/?") == 0 ) {
  1796. Usage();
  1797. goto Done;
  1798. }
  1799. hInst=GetModuleHandle(NULL);
  1800. RtlZeroMemory( &Local, sizeof( TD_DOM_INFO ) );
  1801. RtlZeroMemory( &Remote, sizeof (TD_DOM_INFO ) );
  1802. if(!process_opt(argc,argv, opt_arg)) {
  1803. Status = STATUS_INVALID_PARAMETER;
  1804. Usage();
  1805. goto Done;
  1806. }
  1807. BOOL_ARG(opt_arg,A_LIST, List );
  1808. BOOL_ARG(opt_arg,A_BOTH, Both );
  1809. BOOL_ARG(opt_arg,A_IN, DirIn );
  1810. BOOL_ARG(opt_arg,A_OUT, DirOut );
  1811. BOOL_ARG(opt_arg,A_UNTRUST, Untrust );
  1812. BOOL_ARG(opt_arg,A_CHECK, Check );
  1813. BOOL_ARG(opt_arg,A_VERIFY, Verify );
  1814. BOOL_ARG(opt_arg,A_LOCALONLY,LocalOnly );
  1815. BOOL_ARG(opt_arg,A_DOWNLEVEL,Downlevel );
  1816. BOOL_ARG(opt_arg,A_MIT, Mit );
  1817. BOOL_ARG(opt_arg,A_PARENT, Parent );
  1818. BOOL_ARG(opt_arg,A_DEBUG, Dbg );
  1819. BOOL_ARG(opt_arg,A_FORCE, Force );
  1820. BOOL_ARG(opt_arg,A_NT4, Nt4 );
  1821. BOOL_ARG(opt_arg,A_SIDLIST, SidList );
  1822. //put this after Dbg variable is set
  1823. if(Dbg)
  1824. printf("TRUSTDOM - (ver %ws)\n",VER_FILEVERSION_LSTR);
  1825. //get password (if any)
  1826. if(opt_arg[A_PW].s)
  1827. mbstowcs( PasswordBuff, opt_arg[A_PW].s, strlen( opt_arg[A_PW].s )+1 );
  1828. else PasswordBuff[0]='\0';
  1829. // process normal command line arguments (positional)
  1830. for (j=0,i=1; i<argc; i++) {
  1831. if (!(argv[i][0]=='/' || argv[i][0]=='-')) {
  1832. switch(j) {
  1833. case 0:
  1834. { WCHAR *pws;
  1835. mbstowcs(ADomain, argv[i], strlen(argv[i]) + 1 );
  1836. if((pws=wcschr(ADomain,L','))!=NULL) {
  1837. *pws=L'\0';
  1838. wcscpy(BDomain,pws+1);
  1839. }
  1840. else {
  1841. wcscpy(BDomain,ADomain);
  1842. ADomain[0]=L'\0';
  1843. }
  1844. }
  1845. break;
  1846. }
  1847. j++;
  1848. }
  1849. }
  1850. ParseForDCName(ADomain,ADC);
  1851. ParseForDCName(BDomain,BDC);
  1852. dbgprintf( (0,IDS_DOMARGUMENTS,ADomain,ADC[0]?L":":L"",ADC,BDomain,BDC[0]?L":":L"",BDC) );
  1853. resprintf(2,IDS_WARNING);
  1854. wcscpy(Xbuf,outbuf);
  1855. resprintf(2,IDS_ERROR);
  1856. wcscpy(Ybuf,outbuf);
  1857. //Parameter adjust
  1858. if(SidList)
  1859. List=TRUE;
  1860. //Domain names check:
  1861. { WCHAR *s=NULL;
  1862. BOOL ba, bb;
  1863. if( !(ba=ValidateDomain(s=ADomain)) ||
  1864. !(bb=ValidateDomain(s=BDomain))) {
  1865. resprintf(0,IDS_INVALID_DOMAIN_NAME,s);
  1866. Status = STATUS_INVALID_PARAMETER;
  1867. goto Done;
  1868. }
  1869. }
  1870. // Parameter constraints:
  1871. // '-parent' REQUIRES '-both'
  1872. if (Parent && !Both) {
  1873. if(!Force)
  1874. Status = STATUS_INVALID_PARAMETER;
  1875. resprintf(0,IDS_PARENT_REQ_BOTH,(Force?Xbuf:Ybuf));
  1876. }
  1877. // MIT trusts are always local only
  1878. if (Mit && (!LocalOnly || !Both)) {
  1879. resprintf(0,IDS_MIT_LOCAL_ONLY_BOTH);
  1880. LocalOnly = TRUE;
  1881. Both = TRUE;
  1882. }
  1883. //
  1884. // Validate the parameters
  1885. //
  1886. //specifying both in and out means, yes, '-both'...
  1887. if(DirIn && DirOut)
  1888. Both=TRUE;
  1889. if(List && Mit)
  1890. Status = STATUS_INVALID_PARAMETER;
  1891. if((!List && BDomain[0]==L'\0') || (List && ADomain[0]!=L'\0'))
  1892. Status = STATUS_INVALID_PARAMETER;
  1893. if ( Untrust == TRUE && (Downlevel)) // || Mit || Both ) ) // changed from Both || LocalOnly ||...
  1894. Status = STATUS_INVALID_PARAMETER;
  1895. // if(LocalOnly == TRUE && Both == FALSE)
  1896. // Status = STATUS_INVALID_PARAMETER;;
  1897. if (Mit && (Downlevel || Parent ))
  1898. Status = STATUS_INVALID_PARAMETER;
  1899. // end validating parameters
  1900. if( Status == STATUS_INVALID_PARAMETER ) {
  1901. Usage();
  1902. goto Done;
  1903. }
  1904. if(!Untrust && !List && !Verify) { //check password... otherwise ignore
  1905. if(wcscmp(PasswordBuff,L"*")==0)
  1906. GetPassword(PasswordBuff,1024);
  1907. Password = PasswordBuff;
  1908. }
  1909. ////////////////////////////////////////////////////////////////////////////////
  1910. // list || verify operation: simplified GetDomainInfo scenario...
  1911. ////////////////////////////////////////////////////////////////////////////////
  1912. if ( List ) {
  1913. ULONG i;
  1914. Status = GetDomainInfoForDomain((BDomain[0]==L'\0'?NULL:BDomain),BDC,&Remote, Mit );
  1915. if (!NT_SUCCESS( Status ) )
  1916. goto Done;
  1917. Status = GetTrustLinks( &Remote );
  1918. if (Status!=STATUS_NO_MORE_ENTRIES && !NT_SUCCESS( Status ) )
  1919. goto Done;
  1920. Status = PrintTrustLinks( &Remote );
  1921. goto Done;
  1922. } else
  1923. ////////////////////////////////////////////////////////////////////////////////
  1924. // verify operation
  1925. ////////////////////////////////////////////////////////////////////////////////
  1926. if ( Verify ) {
  1927. Status = VerifyTrusts( BDomain[ 0 ]==L'\0' ? NULL : BDomain, BDC );
  1928. goto Done;
  1929. }
  1930. // regular operation: create/delete trust...
  1931. // get info about the domain(s) involved...
  1932. Status = GetDomainInfoForDomain((ADomain[0]==L'\0'?NULL:ADomain), ADC, &Local, FALSE );
  1933. if ( !NT_SUCCESS( Status ) )
  1934. goto Done;
  1935. Status = GetDomainInfoForDomain( BDomain, BDC, &Remote, Mit );
  1936. if ( !NT_SUCCESS( Status ) ) {
  1937. if(Mit) { //assuming a Unix machine...
  1938. dbgprintf( (0,IDS_DSGETDCNAME_MIT, BDomain) );
  1939. }
  1940. else {
  1941. if(!( Force
  1942. //&& (Status==STATUS_NO_SUCH_DOMAIN)
  1943. //&& LocalOnly && Untrust
  1944. )) // if -force not specified...
  1945. // continue anyway
  1946. goto Done;
  1947. }
  1948. }
  1949. //
  1950. // Ok, now check or or delete or create the trust objects...
  1951. //
  1952. ////////////////////////////////////////////////////////////////////////////////
  1953. // check trust link
  1954. ////////////////////////////////////////////////////////////////////////////////
  1955. if ( Check ) {
  1956. dbgprintf( (0, IDS_PROCESSDOM, GetName(&Local)) );
  1957. Status = CheckTrustLink( &Local, &Remote );
  1958. if (Status!=NERR_Success)
  1959. dbgprintf( (0,IDS_LOCAL_CHK_TRUST_F,Status) );
  1960. if ( !LocalOnly ) {
  1961. dbgprintf( (0, IDS_PROCESSDOM, GetName(&Remote)) );
  1962. Status = CheckTrustLink( &Remote, &Local );
  1963. if (Status!=NERR_Success)
  1964. dbgprintf( (IDS_REMOTE_CHK_TRUST_F,Status) );
  1965. }
  1966. // end check block...
  1967. } else
  1968. ////////////////////////////////////////////////////////////////////////////////
  1969. // delete trust object
  1970. ////////////////////////////////////////////////////////////////////////////////
  1971. if ( Untrust ) {
  1972. dbgprintf( (0, IDS_PROCESSDOM, GetName(&Local)) );
  1973. Status = DeleteTrustLink( &Local, &Remote );
  1974. if (Status!=NERR_Success)
  1975. dbgprintf( (0,IDS_LOCAL_DEL_TRUST_F,Status) );
  1976. if ( !LocalOnly ) {
  1977. dbgprintf( (0, IDS_PROCESSDOM, GetName(&Remote)) );
  1978. Status = DeleteTrustLink( &Remote, &Local );
  1979. if (Status!=NERR_Success)
  1980. dbgprintf( (IDS_REMOTE_DEL_TRUST_F,Status) );
  1981. }
  1982. // end untrust block...
  1983. } else {
  1984. ////////////////////////////////////////////////////////////////////////////
  1985. // create trust links
  1986. ////////////////////////////////////////////////////////////////////////////
  1987. if ( Password == NULL ) {
  1988. Password = L""; // no password specified? then use void password: ""
  1989. }
  1990. if((Local.majver==4 || Remote.majver==4) && !Downlevel) {
  1991. if(!Force)
  1992. Status = STATUS_INVALID_PARAMETER;
  1993. resprintf(0,IDS_NT4_REQ_DOWNLEVEL,(Force?Xbuf:Ybuf));
  1994. if(!NT_SUCCESS(Status))
  1995. goto Done;
  1996. }
  1997. //compute direction of trust based on the values of Both, DirIn, DirOut
  1998. //'Both' has higher priority
  1999. if(Both) {
  2000. DirectionLocal=DirectionRemote=TRUST_DIRECTION_BIDIRECTIONAL;
  2001. } else {
  2002. //default is 'OUTBOUND'... as being DirIn==FALSE and DirOut==TRUE
  2003. DirectionLocal =(DirIn?TRUST_DIRECTION_INBOUND:TRUST_DIRECTION_OUTBOUND);
  2004. DirectionRemote =(DirIn?TRUST_DIRECTION_OUTBOUND:TRUST_DIRECTION_INBOUND);
  2005. }
  2006. swprintf(Xbuf,L"%wZ",GetName(&Local));
  2007. swprintf(Ybuf,L"%wZ",GetName(&Remote));
  2008. //RtlCopyUnicodeString(&uDomNameL,GetName(&Local));
  2009. //RtlCopyUnicodeString(&uDomNameR,GetName(&Remote));
  2010. dbgprintf( (0, IDS_PROCESSDOM, GetName(&Local)) );
  2011. StatusL = CreateTrustLink( &Local, &Remote,
  2012. Password,
  2013. Downlevel,
  2014. Mit,
  2015. Parent,
  2016. DirectionLocal //Both ? TRUST_DIRECTION_BIDIRECTIONAL :
  2017. // TRUST_DIRECTION_OUTBOUND
  2018. );
  2019. if (!NT_SUCCESS(StatusL))
  2020. dbgprintf( (0,IDS_CREATE_TRUST_F, Xbuf,Ybuf,StatusL) );
  2021. //if ( NT_SUCCESS( StatusL ) ) { not needed...
  2022. // LocalCreated = TRUE;
  2023. //}
  2024. if ( NT_SUCCESS( StatusL ) && !LocalOnly ) {
  2025. dbgprintf( (0, IDS_PROCESSDOM, GetName(&Remote)) );
  2026. StatusR = CreateTrustLink( &Remote, &Local,
  2027. Password,
  2028. Downlevel,
  2029. Mit,
  2030. FALSE,
  2031. DirectionRemote //Both ? TRUST_DIRECTION_BIDIRECTIONAL :
  2032. // TRUST_DIRECTION_INBOUND
  2033. );
  2034. if (!NT_SUCCESS(StatusR))
  2035. dbgprintf( (0,IDS_CREATE_TRUST_F, Ybuf,Xbuf, StatusR) );
  2036. }
  2037. if ( !NT_SUCCESS( StatusR ) && NT_SUCCESS( StatusL ) ) { //LocalCreated not used anymore....
  2038. DeleteTrustLink( &Local, &Remote );
  2039. }
  2040. }
  2041. Status = StatusL;
  2042. if( NT_SUCCESS(Status) ) //maybe the 'Remote' attempt failed ?...
  2043. Status = StatusR;
  2044. Done:
  2045. FreeDomainInfo( &Local );
  2046. FreeDomainInfo( &Remote );
  2047. if( NT_SUCCESS( Status ) ) {
  2048. //No message; in this way will be easier also to get a count of the trust links for a list:
  2049. // by example, 'trustdom <dom> -list | findstr ",B," | wc' will get a count of the
  2050. // bidirectional trusts of domain <dom>
  2051. //printf("The command completed successfully\n");
  2052. } else {
  2053. resprintf(0,IDS_COMMAND_FAILED, Status );
  2054. }
  2055. // return 0 for SUCCESS and 1 for some error
  2056. return( !NT_SUCCESS( Status ) );
  2057. }