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.

2541 lines
72 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. default:
  1026. printf("-"); break;
  1027. }
  1028. if(Info->pTDIX[i].TrustAttributes & TRUST_ATTRIBUTE_NON_TRANSITIVE)
  1029. printf(",A_NonTran");
  1030. else printf(",_");
  1031. if(Info->pTDIX[i].TrustAttributes & TRUST_ATTRIBUTE_UPLEVEL_ONLY )
  1032. printf(",A_UpLevelOnly");
  1033. else printf(",_");
  1034. if(Info->pTDIX[i].TrustAttributes & TRUST_ATTRIBUTE_QUARANTINED_DOMAIN )
  1035. printf(",A_QuarantinedDomain");
  1036. else printf(",_");
  1037. if(Info->pTDIX[i].TrustAttributes & TRUST_ATTRIBUTE_FOREST_TRANSITIVE)
  1038. printf(",A_ForestTrust");
  1039. else printf(",_");
  1040. if(Info->pTDIX[i].TrustAttributes & TRUST_ATTRIBUTE_CROSS_ORGANIZATION)
  1041. printf(",A_CrossFederation");
  1042. else printf(",_");
  1043. if(Info->pTDIX[i].TrustAttributes & TRUST_ATTRIBUTE_WITHIN_FOREST)
  1044. printf(",A_WithinForest");
  1045. else printf(",_");
  1046. if(Info->pTDIX[i].TrustAttributes & TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL)
  1047. printf(",A_TreatAsExternal");
  1048. else printf(",_");
  1049. if(SidList) {
  1050. printf(",");
  1051. PrintSID(Info->pTDIX[i].Sid);
  1052. }
  1053. printf("\n");
  1054. }
  1055. }
  1056. else {
  1057. //Info->majver<=4
  1058. int shot;
  1059. struct bidir_st *p=NULL, *q=NULL;
  1060. if((p=calloc(Info->TIcEntries,sizeof(struct bidir_st)))==NULL)
  1061. return(ERROR_NOT_ENOUGH_MEMORY);
  1062. //for(q=p,i=0; i<Info->TIcEntries; q++,i++) {
  1063. for(q=p,shot=0; shot<Info->nTIs; shot++) {
  1064. for(i=0; i<Info->pTIs[shot].count; i++,q++) {
  1065. WCHAR buf[1024];
  1066. swprintf(buf,L"%wZ",&Info->pTIs[shot].pTI[i].Name);
  1067. for(j=0; j<Info->UI1cEntries; j++)
  1068. if(wcscmp(buf,CutDlrFromName(Info->pUI1[j].usri1_name))==0)
  1069. break;
  1070. if((q->index=j)<Info->UI1cEntries) //found...
  1071. q->type='B'; //actually it's a Bidir link...
  1072. else q->type='O'; //or this is a "true" Outbound...
  1073. }
  1074. }
  1075. //print Outbound and Bidirectional links
  1076. //for(q=p,i=0; i<Info->TIcEntries; q++,i++)
  1077. for(q=p,shot=0; shot<Info->nTIs; shot++)
  1078. for(i=0; i<Info->pTIs[shot].count; i++,q++)
  1079. printf("%-32wZ,%c,T_downlevel,_,_,_,_\n",&Info->pTIs[shot].pTI[i].Name,q->type);
  1080. qsort(p,Info->TIcEntries,sizeof(struct bidir_st),cmpbidir);
  1081. //print Inbound links
  1082. for(q=p,j=i=0; i<Info->UI1cEntries; i++) {
  1083. if(j<Info->TIcEntries && q->index==i) { //if it was a Bidirectional, it was already printed...
  1084. j++; q++;
  1085. continue;
  1086. }
  1087. printf("%-32ws,I,T_downlevel,_,_,_,_\n",CutDlrFromName(Info->pUI1[i].usri1_name));
  1088. }
  1089. if(p!=NULL)
  1090. free(p);
  1091. }
  1092. return( STATUS_SUCCESS );
  1093. }
  1094. NTSTATUS
  1095. CreateNT5TrustDomObject(
  1096. IN PTD_DOM_INFO Local,
  1097. IN PTD_DOM_INFO Remote,
  1098. IN PWSTR Password,
  1099. IN BOOLEAN Downlevel,
  1100. IN BOOLEAN Mit,
  1101. IN ULONG Direction
  1102. )
  1103. /*++
  1104. Routine Description:
  1105. Creates the trusted domain object on an NT5 domain (DS based)
  1106. Arguments:
  1107. Local -- Information about the domain doing the trust
  1108. Remote -- Information about the domain being trusted
  1109. Password -- Password to set on the trust
  1110. Downlevel -- If TRUE, create this as a downlevel trust
  1111. Mit -- If TRUE, creates this as an Mit style trust
  1112. Direction -- Which direction to make the link in.
  1113. Return Value:
  1114. STATUS_SUCCESS -- Success
  1115. --*/
  1116. {
  1117. NTSTATUS Status = STATUS_SUCCESS;
  1118. WCHAR Domain[1024]={L'\0'};
  1119. WCHAR DnsDomain[1024]={L'\0'};
  1120. TRUSTED_DOMAIN_INFORMATION_EX TDIEx;
  1121. LSA_AUTH_INFORMATION AuthData;
  1122. TRUSTED_DOMAIN_AUTH_INFORMATION AuthInfoEx;
  1123. PSID Sid = NULL;
  1124. swprintf(Domain,L"%wZ",GetFlatName(Remote));
  1125. swprintf(DnsDomain,L"%wZ",GetName(Remote));
  1126. Status = NtQuerySystemTime( &AuthData.LastUpdateTime );
  1127. if ( !NT_SUCCESS( Status ) ) {
  1128. return( Status );
  1129. }
  1130. AuthData.AuthType = TRUST_AUTH_TYPE_CLEAR;
  1131. AuthData.AuthInfoLength = wcslen( Password ) * sizeof( WCHAR );
  1132. AuthData.AuthInfo = (PUCHAR)Password;
  1133. RtlZeroMemory( &AuthInfoEx, sizeof( LSA_AUTH_INFORMATION ) );
  1134. if ( Direction & TRUST_DIRECTION_INBOUND ) {
  1135. AuthInfoEx.IncomingAuthInfos = 1;
  1136. AuthInfoEx.IncomingAuthenticationInformation = &AuthData;
  1137. AuthInfoEx.IncomingPreviousAuthenticationInformation = NULL;
  1138. }
  1139. if ( Direction & TRUST_DIRECTION_OUTBOUND ) {
  1140. AuthInfoEx.OutgoingAuthInfos = 1;
  1141. AuthInfoEx.OutgoingAuthenticationInformation = &AuthData;
  1142. AuthInfoEx.OutgoingPreviousAuthenticationInformation = NULL;
  1143. }
  1144. if (!Mit)
  1145. {
  1146. RtlCopyMemory( &TDIEx.Name, GetName(Remote), sizeof( UNICODE_STRING ) );
  1147. RtlCopyMemory( &TDIEx.FlatName, GetFlatName(Remote), sizeof( UNICODE_STRING ) );
  1148. switch(Remote->DomInfoType) {
  1149. case DNS: TDIEx.Sid = Remote->u.DnsDomainInfo->Sid;
  1150. break;
  1151. case Primary: TDIEx.Sid = Remote->u.PrimaryDomainInfo->Sid;
  1152. break;
  1153. default: Status = GenerateRandomSID( &Sid);
  1154. if (!NT_SUCCESS(Status))
  1155. {
  1156. return(Status);
  1157. }
  1158. TDIEx.Sid = Sid;
  1159. break;
  1160. }
  1161. //TDIEx.Sid = (Remote->DomInfoType==DNS?Remote->u.DnsDomainInfo->Sid:Remote->u.PrimaryDomainInfo->Sid);
  1162. }
  1163. else
  1164. {
  1165. // printf("****Set %ws for the Name and FlatName in the trust object... GetFlatName(Local)=%wZ\n",
  1166. // Domain,GetFlatName(Local));
  1167. RtlInitUnicodeString(
  1168. &TDIEx.Name,
  1169. Domain
  1170. );
  1171. RtlInitUnicodeString(
  1172. &TDIEx.FlatName,
  1173. Domain
  1174. );
  1175. Status = GenerateRandomSID( &Sid);
  1176. if (!NT_SUCCESS(Status))
  1177. {
  1178. return(Status);
  1179. }
  1180. TDIEx.Sid = Sid;
  1181. }
  1182. TDIEx.TrustDirection = Direction;
  1183. TDIEx.TrustType = Mit ? TRUST_TYPE_MIT : (Downlevel ? TRUST_TYPE_DOWNLEVEL : TRUST_TYPE_UPLEVEL);
  1184. TDIEx.TrustAttributes = 0;
  1185. Status = LsaCreateTrustedDomainEx( Local->Policy,
  1186. &TDIEx,
  1187. &AuthInfoEx,
  1188. TRUSTED_ALL_ACCESS,
  1189. &Local->TrustedDomain );
  1190. if (!NT_SUCCESS(Status)) {
  1191. dbgprintf( (0,IDS_LSACREATETRUSTEDDOMAINEX_F, GetName(Local), DnsDomain, Status) );
  1192. if(Status==STATUS_OBJECT_NAME_COLLISION)
  1193. dbgprintf( (0,IDS_STATUS_OBJECT_NAME_COLLISION, GetName(Local), DnsDomain) );
  1194. }
  1195. else LsaClose(Local->TrustedDomain); //not interested in the actual handle...
  1196. if (Sid != NULL)
  1197. {
  1198. RtlFreeSid(Sid);
  1199. }
  1200. return( Status );
  1201. }
  1202. NTSTATUS
  1203. CreateTrustLink(
  1204. IN PTD_DOM_INFO pInfoA,
  1205. IN PTD_DOM_INFO pInfoB,
  1206. IN PWSTR Password,
  1207. IN BOOLEAN Downlevel,
  1208. IN BOOLEAN Mit,
  1209. IN BOOLEAN ParentChild,
  1210. IN ULONG Direction
  1211. )
  1212. {
  1213. NET_API_STATUS netstatus=NERR_Success;
  1214. NTSTATUS Status = STATUS_SUCCESS;
  1215. PWSTR pDomain=NULL;
  1216. if( !Force // if -force was NOT specified...
  1217. &&
  1218. !Mit // for a non-MIT trust...
  1219. &&
  1220. (pInfoA->DomInfoType==Minimal || pInfoB->DomInfoType==Minimal)
  1221. // creating links not supported in 'Minimal' mode...
  1222. )
  1223. return( STATUS_UNSUCCESSFUL );
  1224. if(pInfoA->majver>=5) {
  1225. Status = CreateNT5TrustDomObject(
  1226. pInfoA,
  1227. pInfoB,
  1228. Password,
  1229. Downlevel,Mit,Direction
  1230. );
  1231. return( Status );
  1232. }
  1233. ////////////////////////////////////////////////////////////////////////
  1234. //for a NT4 domain...
  1235. if(Mit || ParentChild)
  1236. return (STATUS_INVALID_PARAMETER);
  1237. if(Direction & TRUST_DIRECTION_INBOUND) {
  1238. USER_INFO_1 UI1;
  1239. DWORD dwParmErr=0xffffffff;
  1240. memset(&UI1,0,sizeof(UI1));
  1241. pDomain=AddDlrToDomainName(pInfoB);
  1242. // Create the necessary SAM account.
  1243. UI1.usri1_name = pDomain;
  1244. UI1.usri1_password = Password;
  1245. UI1.usri1_password_age = 0;
  1246. UI1.usri1_priv = USER_PRIV_USER;
  1247. UI1.usri1_home_dir = NULL;
  1248. UI1.usri1_comment = NULL;
  1249. UI1.usri1_flags = UF_INTERDOMAIN_TRUST_ACCOUNT | UF_SCRIPT;
  1250. UI1.usri1_script_path = NULL;
  1251. netstatus = NetUserAdd(
  1252. MakeSrvName(pInfoA->DCName),
  1253. 1,
  1254. (LPBYTE)&UI1,
  1255. &dwParmErr
  1256. );
  1257. if(netstatus != NERR_Success) {
  1258. resprintf(0,IDS_NETUSERADD_F,pInfoA->DCName,pDomain,netstatus);
  1259. if(netstatus==NERR_UserExists)
  1260. resprintf(0,IDS_NERR_UserExists,pInfoA->DCName,pDomain);
  1261. goto Done;
  1262. }
  1263. }
  1264. if(Direction & TRUST_DIRECTION_OUTBOUND) {
  1265. LSA_TRUST_INFORMATION TI;
  1266. PUNICODE_STRING puSecret;
  1267. UNICODE_STRING uPass;
  1268. LSA_HANDLE hSecret;
  1269. swprintf(Domain,L"%wZ",GetFlatName(pInfoB));
  1270. RtlInitUnicodeString(&TI.Name,Domain);
  1271. { PSID Sid = NULL;
  1272. switch(pInfoB->DomInfoType) {
  1273. case DNS: TI.Sid = pInfoB->u.DnsDomainInfo->Sid;
  1274. break;
  1275. case Primary: TI.Sid = pInfoB->u.PrimaryDomainInfo->Sid;
  1276. break;
  1277. default: Status = GenerateRandomSID( &Sid);
  1278. if (!NT_SUCCESS(Status))
  1279. {
  1280. return(Status);
  1281. }
  1282. TI.Sid = Sid;
  1283. break;
  1284. }
  1285. }
  1286. //TI.Sid=(pInfoB->DomInfoType==DNS?pInfoB->u.DnsDomainInfo->Sid:pInfoB->u.PrimaryDomainInfo->Sid);
  1287. Status = LsaCreateTrustedDomain(
  1288. pInfoA->Policy,
  1289. &TI,
  1290. TRUSTED_ALL_ACCESS,
  1291. &pInfoA->TrustedDomain
  1292. );
  1293. if( !NT_SUCCESS(Status)) {
  1294. resprintf(0,IDS_LSACREATETRUSTEDDOMAIN_F,Status);
  1295. goto Done;
  1296. }
  1297. else LsaClose(pInfoA->TrustedDomain); //not interested in the actual handle...
  1298. puSecret=MakeSecretName(pInfoB);
  1299. Status = LsaCreateSecret(
  1300. pInfoA->Policy,
  1301. puSecret,
  1302. SECRET_ALL_ACCESS,
  1303. &hSecret
  1304. );
  1305. if(!NT_SUCCESS(Status)) {
  1306. resprintf(0,IDS_LSACREATESECRET_F,Status);
  1307. goto Done;
  1308. }
  1309. RtlInitUnicodeString(&uPass,Password);
  1310. Status=LsaSetSecret(
  1311. hSecret,
  1312. &uPass,
  1313. NULL
  1314. );
  1315. if(!NT_SUCCESS(Status)) {
  1316. resprintf(0,IDS_LSASETSECRET_F,Status);
  1317. LsaDelete(hSecret); hSecret=NULL;
  1318. goto Done;
  1319. }
  1320. if(hSecret!=NULL)
  1321. LsaClose(hSecret);
  1322. }
  1323. Done:
  1324. // if(pInfoA->TrustedDomain!=NULL)
  1325. // LsaClose(pInfoA->TrustedDomain);
  1326. return(Status);
  1327. }
  1328. NTSTATUS
  1329. DeleteTrustLink(
  1330. IN PTD_DOM_INFO pInfoA,
  1331. IN PTD_DOM_INFO pInfoB
  1332. )
  1333. /*++
  1334. Routine Description:
  1335. Deletes on A trusted domain things related to a trust to B
  1336. Return Value:
  1337. STATUS_SUCCESS -- Success
  1338. --*/
  1339. {
  1340. NET_API_STATUS netstatus=NERR_Success;
  1341. NTSTATUS Status=STATUS_SUCCESS;
  1342. //#define NO_TRUST_OBJECTS 1
  1343. //#define NO_SECRETS 2
  1344. //#define NO_TRUST_ACCOUNTS 4
  1345. // DWORD dwFlag=0;
  1346. ULONG i, ix=0;
  1347. PSID sid=NULL;
  1348. PTRUSTED_DOMAIN_INFORMATION_EX pTDIx = NULL;
  1349. PLSA_UNICODE_STRING puDomBName=GetName(pInfoB);
  1350. PLSA_UNICODE_STRING puDomBFlatName=GetFlatName(pInfoB);
  1351. PLSA_UNICODE_STRING puSecret;
  1352. dbgprintf( (0,IDS_DELTRUSTFROMTO,GetName(pInfoA),puDomBName) );
  1353. Status = GetTrustLinks(pInfoA);
  1354. if(!NT_SUCCESS(Status)) {
  1355. resprintf(0,IDS_GETTRUSTLINKS_F,GetName(pInfoA),Status);
  1356. return(Status);
  1357. }
  1358. //try to find a trust link to B...
  1359. if(pInfoA->majver>=5) {
  1360. // now try to get a LSA_HANDLE to a (possible) trust object with this domain...
  1361. // if not found any, that Info->TrustedDomain will remain NULL
  1362. Status = LsaQueryTrustedDomainInfoByName(
  1363. pInfoA->Policy,
  1364. puDomBName, //IN PLSA_UNICODE_STRING TrustedDomainName
  1365. TrustedDomainInformationEx, //IN TRUSTED_INFORMATION_CLASS InformationClass,
  1366. &pTDIx //OUT PVOID *Buffer
  1367. );
  1368. if ( !NT_SUCCESS( Status ) ) {
  1369. if(Status==STATUS_OBJECT_NAME_NOT_FOUND) {
  1370. pInfoA->TrustedDomain=NULL;
  1371. dbgprintf( (0,IDS_NO_TRUST_OBJECT_D,GetName(pInfoA),puDomBName) );
  1372. Status=STATUS_SUCCESS;
  1373. }
  1374. else resprintf(0,IDS_LSAQUERYTRUSTEDDOMAININFOBYNAME_F,GetName(pInfoA),puDomBName,Status);
  1375. goto cleanup;
  1376. }
  1377. if(pTDIx->Sid==NULL)
  1378. dbgprintf( (0,IDS_LSAQUERYNULLSID) ); //"NULL sid returned by LsaQueryTrustedDomainInfoByName\n"
  1379. sid=pTDIx->Sid;
  1380. //check to see if the trusted domain object can be opened with that sid...
  1381. if(sid!=NULL) {
  1382. LSA_HANDLE td;
  1383. Status=LsaOpenTrustedDomain(pInfoA->Policy,
  1384. sid,TRUSTED_ALL_ACCESS,&td);
  1385. if(NT_SUCCESS( Status )) // if it was ok...
  1386. LsaClose(td); // ...just close the handle (leave the following code to open it again later)
  1387. else { // if failed...
  1388. if(Status==STATUS_INVALID_PARAMETER && Force) {
  1389. printf("LsaOpenTrustedDomain for the trust to %wZ failed with STATUS_INVALID_PARAMETER (i.e. the sid is bad)\n"
  1390. "Trying to set a valid sid...\n",puDomBName);
  1391. // if was STATUS_INVALID_PARAMETER (i.e. the sid) and '-overwritesid' option used...
  1392. RtlFreeSid(sid); // free the old sid
  1393. sid=NULL; // make it NULL as a signal to the next 'if' (see below) to
  1394. } // pick it up and set a new random valid sid in its place
  1395. }
  1396. }
  1397. if(sid==NULL) {
  1398. // try to put a sid THERE ...
  1399. Status = GenerateRandomSID ( &pTDIx->Sid );
  1400. if (!NT_SUCCESS( Status ))
  1401. goto cleanup;
  1402. Status = LsaSetTrustedDomainInfoByName(
  1403. pInfoA->Policy,
  1404. puDomBName, //IN PLSA_UNICODE_STRING TrustedDomainName
  1405. TrustedDomainInformationEx, //IN TRUSTED_INFORMATION_CLASS InformationClass,
  1406. pTDIx //IN PVOID Buffer
  1407. );
  1408. if(!NT_SUCCESS( Status )) {
  1409. resprintf(0,IDS_LSASETTRUSTEDDOMAININFOBYNAME_F,GetName(pInfoA),puDomBName,Status);
  1410. goto cleanup;
  1411. }
  1412. sid=pTDIx->Sid;
  1413. if(sid==NULL)
  1414. resprintf(0,IDS_LSASETNULLSID); //"LsaSetTrustedDomainInfoByName: NULL sid\n"
  1415. }
  1416. }
  1417. else { // pInfoA->majver<=4
  1418. //check for Outbound....
  1419. int shot;
  1420. //for(ix=0; ix<pInfoA->TIcEntries; ix++)
  1421. for(shot=0; shot<pInfoA->nTIs; shot++)
  1422. for(ix=0; ix<pInfoA->pTIs[shot].count; ix++)
  1423. if(RtlEqualUnicodeString(&pInfoA->pTIs[shot].pTI[ix].Name,puDomBFlatName,TRUE))
  1424. //it was FALSE, i.e. case sensitive
  1425. goto out_of_loop;
  1426. out_of_loop:
  1427. if(ix<pInfoA->TIcEntries)
  1428. sid=pInfoA->pTIs[shot].pTI[ix].Sid;
  1429. else {
  1430. printf("No OUTBOUND trust to %wZ found...\n",puDomBFlatName);
  1431. }
  1432. }
  1433. if(sid==NULL)
  1434. dbgprintf( (0,IDS_NULLSID) ); //"#### NULL sid\n"
  1435. if(sid!=NULL) {
  1436. Status=LsaOpenTrustedDomain(
  1437. pInfoA->Policy,
  1438. sid,
  1439. TRUSTED_ALL_ACCESS,
  1440. &pInfoA->TrustedDomain
  1441. );
  1442. //printf("Handle=0x%08lx (Status: 0x%08lx)\n",pInfoA->TrustedDomain,Status);
  1443. if(!NT_SUCCESS(Status)) {
  1444. resprintf(0,IDS_LSAOPENTRUSTEDDOMAIN_F,Status);
  1445. //return(Status);
  1446. }
  1447. dbgprintf( (0,IDS_LSATRUSTHANDLE,pInfoA->TrustedDomain,Status) );
  1448. }
  1449. else {
  1450. if( //pInfoA->majver<=4 &&
  1451. ix<pInfoA->TIcEntries) {
  1452. resprintf(0,IDS_NONNULL_SID,puDomBName);
  1453. Status=STATUS_INVALID_SID;
  1454. }
  1455. else //simply no trust objects...
  1456. Status=STATUS_SUCCESS;
  1457. }
  1458. if(pInfoA->TrustedDomain) {
  1459. dbgprintf( (0,IDS_LSADELOBJ,pInfoA->TrustedDomain) );
  1460. Status = LsaDelete( pInfoA->TrustedDomain );
  1461. }
  1462. if (!NT_SUCCESS(Status))
  1463. dbgprintf( (0,IDS_DELETION_F,GetName(pInfoA), Status) );
  1464. //NT4 only section...
  1465. if(pInfoA->majver<=4) {
  1466. LSA_HANDLE hSecret;
  1467. //delete secret thing...
  1468. puSecret=MakeSecretName(pInfoB);
  1469. Status = LsaOpenSecret(
  1470. pInfoA->Policy,
  1471. puSecret,
  1472. SECRET_ALL_ACCESS,
  1473. &hSecret
  1474. );
  1475. if(Status==STATUS_OBJECT_NAME_NOT_FOUND) {
  1476. dbgprintf( (0,IDS_SECRET_NOT_FOUND_D,puSecret) );
  1477. Status=STATUS_SUCCESS;
  1478. }
  1479. else {
  1480. if(!NT_SUCCESS(Status)) {
  1481. resprintf(0,IDS_LSAOPENSECRET_F,Status);
  1482. }
  1483. else {
  1484. Status = LsaDelete(hSecret); hSecret=NULL;
  1485. if(!NT_SUCCESS(Status))
  1486. resprintf(0,IDS_LSADELETE_F,puSecret,Status);
  1487. }
  1488. }
  1489. //delete Interdomain Trust Account....
  1490. netstatus = NetUserDel(
  1491. MakeSrvName(pInfoA->DCName),
  1492. AddDlrToDomainName(pInfoB)
  1493. );
  1494. if(netstatus!=NERR_Success && netstatus!=NERR_UserNotFound) {
  1495. resprintf(0,IDS_NETUSERDEL_F,AddDlrToDomainName(pInfoB),netstatus);
  1496. Status=STATUS_UNSUCCESSFUL;
  1497. }
  1498. }
  1499. cleanup:
  1500. if(pTDIx!=NULL)
  1501. LsaFreeMemory(pTDIx);
  1502. if(sid!=NULL)
  1503. RtlFreeSid(sid);
  1504. return( Status );
  1505. }
  1506. NTSTATUS
  1507. CheckTrustLink(
  1508. IN PTD_DOM_INFO pInfoA,
  1509. IN PTD_DOM_INFO pInfoB
  1510. )
  1511. /*++
  1512. Routine Description:
  1513. Checks on A trusted domain sids related to a trust to B
  1514. Return Value:
  1515. STATUS_SUCCESS -- Success
  1516. --*/
  1517. {
  1518. NET_API_STATUS netstatus=NERR_Success;
  1519. NTSTATUS Status=STATUS_SUCCESS;
  1520. PSID sid=NULL, sidb=NULL;
  1521. BOOL UnknownRemoteSid=FALSE;
  1522. PTRUSTED_DOMAIN_INFORMATION_EX pTDIx = NULL;
  1523. PLSA_UNICODE_STRING puDomBName=GetName(pInfoB);
  1524. PLSA_UNICODE_STRING puDomBFlatName=GetFlatName(pInfoB);
  1525. dbgprintf( (0,IDS_CHKTRUSTFROMTO,GetName(pInfoA),puDomBName) );
  1526. //try to find a trust link to B...
  1527. if(pInfoA->majver>=5) {
  1528. // now try to get a LSA_HANDLE to a (possible) trust object with this domain...
  1529. // if not found any, that Info->TrustedDomain will remain NULL
  1530. Status = LsaQueryTrustedDomainInfoByName(
  1531. pInfoA->Policy,
  1532. puDomBName, //IN PLSA_UNICODE_STRING TrustedDomainName
  1533. TrustedDomainInformationEx, //IN TRUSTED_INFORMATION_CLASS InformationClass,
  1534. &pTDIx //OUT PVOID *Buffer
  1535. );
  1536. if ( !NT_SUCCESS( Status ) ) {
  1537. if(Status==STATUS_OBJECT_NAME_NOT_FOUND) {
  1538. pInfoA->TrustedDomain=NULL;
  1539. dbgprintf( (0,IDS_NO_TRUST_OBJECT_D,GetName(pInfoA),puDomBName) );
  1540. Status=STATUS_SUCCESS;
  1541. }
  1542. else resprintf(0,IDS_LSAQUERYTRUSTEDDOMAININFOBYNAME_F,GetName(pInfoA),puDomBName,Status);
  1543. goto cleanup;
  1544. }
  1545. sid=pTDIx->Sid;
  1546. }
  1547. else { // pInfoA->majver<=4
  1548. //check for Outbound....
  1549. int shot;
  1550. ULONG i;
  1551. for(shot=0; shot<pInfoA->nTIs; shot++)
  1552. for(i=0; i<pInfoA->pTIs[shot].count; i++)
  1553. if(RtlEqualUnicodeString(&pInfoA->pTIs[shot].pTI[i].Name,puDomBFlatName,TRUE))
  1554. //it was FALSE, i.e. case sensitive
  1555. goto out_of_loop;
  1556. out_of_loop:
  1557. if(i<pInfoA->TIcEntries)
  1558. sid=pInfoA->pTIs[shot].pTI[i].Sid;
  1559. }
  1560. switch(pInfoB->DomInfoType) {
  1561. case DNS: sidb = pInfoB->u.DnsDomainInfo->Sid;
  1562. break;
  1563. case Primary: sidb = pInfoB->u.PrimaryDomainInfo->Sid;
  1564. break;
  1565. default: sidb=NULL;
  1566. UnknownRemoteSid=TRUE;
  1567. break;
  1568. }
  1569. //now sid contains the Sid of the trust object, if any... (on NT4, only the OUTBOUND
  1570. //end of the trust has a trust object...)
  1571. //Print them and compare them...
  1572. printf("TDO on %wZ: sid:\t",GetName(pInfoA));
  1573. PrintSID(sid);
  1574. printf("\n");
  1575. if(UnknownRemoteSid) {
  1576. if(pInfoB->majver<=4)
  1577. printf("Domain %wZ does not have a trust object (possibly an NT4 only with an INBOUND trust)\n",puDomBName);
  1578. else
  1579. printf("Sid for domain %wZ is unknown (possible localonly used or error getting Dns/Primary DomainInfo)",puDomBName);
  1580. }
  1581. else {
  1582. if(sid!=NULL && IsValidSid(sid) && sidb!=NULL && IsValidSid(sidb)) {
  1583. if(EqualSid(sid,sidb))
  1584. printf("Sid on %wZ is the same:\t",puDomBName);
  1585. else printf("Sid on %wZ is different:\t",puDomBName);
  1586. }
  1587. else {
  1588. printf("Sid on %wZ: ",puDomBName);
  1589. }
  1590. PrintSID(sidb);
  1591. }
  1592. printf("\n");
  1593. cleanup:
  1594. if(pTDIx!=NULL)
  1595. LsaFreeMemory(pTDIx);
  1596. return( Status );
  1597. }
  1598. void ParseForDCName(WCHAR DomBuf[], WCHAR DCBuf[])
  1599. {
  1600. WCHAR *pw;
  1601. DCBuf[0]=L'\0';
  1602. wcstok(DomBuf,L":");
  1603. if((pw=wcstok(NULL,L":"))!=NULL)
  1604. wcscpy(DCBuf,pw);
  1605. if(DomBuf[0]==L'*' || wcscmp(DomBuf,L"(local)")==0)
  1606. DomBuf[0]=L'\0';
  1607. }
  1608. //the NameValidate stuff below taken from icanon.h
  1609. NET_API_STATUS
  1610. NET_API_FUNCTION
  1611. I_NetNameValidate(
  1612. IN LPWSTR ServerName OPTIONAL,
  1613. IN LPWSTR Name,
  1614. IN DWORD NameType,
  1615. IN DWORD Flags );
  1616. //NameType:
  1617. #define NAMETYPE_DOMAIN 6
  1618. //Flags:
  1619. //#define LM2X_COMPATIBLE 0x80000000L
  1620. #ifdef COMMENT
  1621. #define CTRL_CHARS_0 L"\001\002\003\004\005\006\007"
  1622. #define CTRL_CHARS_1 L"\010\011\012\013\014\015\016\017"
  1623. #define CTRL_CHARS_2 L"\020\021\022\023\024\025\026\027"
  1624. #define CTRL_CHARS_3 L"\030\031\032\033\034\035\036\037"
  1625. #define CTRL_CHARS_STR CTRL_CHARS_0 CTRL_CHARS_1 CTRL_CHARS_2 CTRL_CHARS_3
  1626. #define ILLEGAL_DOMAIN_CHARS_STR
  1627. #define ILLEGAL_DOMAIN_NAME_CHARS_STR L"\"/\\[]:|<>+;,?" CTRL_CHARS_STR L"*" L" "
  1628. #endif //COMMENT
  1629. BOOL ValidateDomain(WCHAR DomBuf[])
  1630. { WCHAR Buf[MAX_PATH + 1]= { L'\0' };
  1631. WCHAR *p;
  1632. int DomBuf_len, oem_name_len;
  1633. NET_API_STATUS netstatus=NERR_Success;
  1634. if(DomBuf==NULL || DomBuf[0]==L'\0')
  1635. return(TRUE);
  1636. wcscpy(Buf,DomBuf);
  1637. //for DNS name, test each component; for a flat name, there's already only one...
  1638. for(p=wcstok(Buf,L"."); p!=NULL; p=wcstok(NULL,L"."))
  1639. if((netstatus=I_NetNameValidate(NULL,p,NAMETYPE_DOMAIN,0))!=NERR_Success)
  1640. return(FALSE);
  1641. return(TRUE);
  1642. #ifdef COMMENT
  1643. DomBuf_len=wcslen(DomBuf);
  1644. // oem_name_len : length in bytes in oem character set
  1645. // name_len : ifdef UNICODE
  1646. // character length in unicode
  1647. // else
  1648. // length in bytes in oem character set
  1649. //
  1650. {
  1651. BOOL fUsedDefault;
  1652. oem_name_len = WideCharToMultiByte(
  1653. CP_OEMCP, // UINT CodePage
  1654. 0, // DWORD dwFlags
  1655. DomBuf, // LPWSTR lpWideChar
  1656. DomBuf_len, // int cchWideChar
  1657. NULL, // LPSTR lpMultiByteStr
  1658. 0, // int cchMultiByte
  1659. NULL, // use system default char
  1660. &fUsedDefault); //
  1661. }
  1662. if(oem_name_len<1 || oem_name_len>=DNLEN)
  1663. return(FALSE);
  1664. if(wcscspn(DomBuf,ILLEGAL_DOMAIN_NAME_CHARS_STR) < DomBuf_len)
  1665. return(FALSE);
  1666. return(TRUE);
  1667. #endif //COMMENT
  1668. }
  1669. #define ARG_CASE_S 0x8000 // case sensitive argument
  1670. #define BOOL_ARG(argvec,a_index,var) {if((argvec)[(a_index)].b) (var)=(BOOLEAN)((argvec)[(a_index)].b);}
  1671. enum e_arg_type { ARG_S, ARG_U, ARG_B, ARG_I, ARG_L, ARG_UD };
  1672. struct _arg_st {
  1673. char *name;
  1674. union {
  1675. char *s;
  1676. ULONG u;
  1677. BOOL b;
  1678. int i;
  1679. long l;
  1680. void (*fct)(char *);
  1681. };
  1682. enum e_arg_type t;
  1683. };
  1684. #define NELEMS(a) (sizeof(a)/sizeof(a[0]))
  1685. int process_opt(int argc, char **argv, struct _arg_st arg[])
  1686. { // command line parameters processing
  1687. int i,j,k; char *p; struct _arg_st *pa;
  1688. int r=1;
  1689. // process options
  1690. for (i=1; i<argc; i++) {
  1691. if (argv[i][0]=='/' || argv[i][0]=='-') {
  1692. p=strtok(argv[i]+1,":");
  1693. for(j=0; arg[j].name!=NULL; j++) {
  1694. if(p!=NULL && ( ((arg[j].t & ARG_CASE_S) && strcmp(p,arg[j].name)==0) ||
  1695. _stricmp(p,arg[j].name)==0 ) )
  1696. break;
  1697. }
  1698. if(arg[j].name==NULL) {
  1699. resprintf(1,IDS_UNKNOWN_OPTION,p);
  1700. r=0;
  1701. continue;
  1702. }
  1703. switch(arg[j].t)
  1704. {
  1705. case ARG_B:
  1706. if( (p=strtok(NULL,""))==NULL
  1707. || _stricmp(p,"on")==0
  1708. || _stricmp(p,"true")==0)
  1709. arg[j].b=TRUE;
  1710. else arg[j].b=FALSE;
  1711. break;
  1712. case ARG_S:
  1713. if((p=strtok(NULL,""))!=NULL)
  1714. arg[j].s=_strdup(p);
  1715. else arg[j].s=NULL;
  1716. break;
  1717. case ARG_U:
  1718. if((p=strtok(NULL,""))!=NULL)
  1719. arg[j].u=(ULONG)atol(p);
  1720. break;
  1721. case ARG_L:
  1722. if((p=strtok(NULL,""))!=NULL)
  1723. arg[j].l=atol(p);
  1724. break;
  1725. case ARG_I:
  1726. if((p=strtok(NULL,""))!=NULL)
  1727. arg[j].i=atoi(p);
  1728. break;
  1729. case ARG_UD:
  1730. p=strtok(NULL,"");
  1731. (*arg[j].fct)(p);
  1732. break;
  1733. }
  1734. }
  1735. }
  1736. return(r);
  1737. }
  1738. // options
  1739. enum e_arg_idx { A_LIST, A_BOTH, A_IN, A_OUT,
  1740. A_UNTRUST, A_CHECK,
  1741. A_VERIFY,
  1742. A_LOCALONLY, A_DOWNLEVEL, A_MIT, A_PARENT,
  1743. A_DEBUG,
  1744. A_PW,
  1745. A_FORCE,
  1746. A_NT4,
  1747. A_SIDLIST,
  1748. A_LASTARG };
  1749. struct _arg_st opt_arg[]={
  1750. {"list", NULL, ARG_B}, // A_LIST
  1751. {"both", NULL, ARG_B}, // A_BOTH
  1752. {"in", NULL, ARG_B}, // A_IN
  1753. {"out", NULL, ARG_B}, // A_OUT
  1754. {"untrust", NULL, ARG_B}, // A_UNTRUST
  1755. {"sidcheck", NULL, ARG_B}, // A_CHECK
  1756. {"verify", NULL, ARG_B}, // A_VERIFY
  1757. {"localonly", NULL, ARG_B}, // A_LOCALONLY
  1758. {"downlevel", NULL, ARG_B}, // A_DOWNLEVEL
  1759. {"mit", NULL, ARG_B}, // A_MIT
  1760. {"parent", NULL, ARG_B}, // A_PARENT
  1761. {"debug", NULL, ARG_B}, // A_DEBUG
  1762. {"pw", NULL, ARG_S}, // A_PW
  1763. {"force", NULL, ARG_B}, // A_FORCE
  1764. {"nt4", NULL, ARG_B}, // A_NT4
  1765. {"sidlist", NULL, ARG_B}, // A_SIDLIST
  1766. {NULL, NULL}
  1767. };
  1768. INT
  1769. __cdecl main ( // it was _CRTAPI1
  1770. int argc,
  1771. char **argv)
  1772. {
  1773. NTSTATUS Status = STATUS_SUCCESS;
  1774. NTSTATUS StatusL = STATUS_SUCCESS;
  1775. NTSTATUS StatusR = STATUS_SUCCESS;
  1776. WCHAR ADomain[MAX_PATH + 1]= { L'\0' };
  1777. WCHAR BDomain[MAX_PATH + 1]= { L'\0' };
  1778. WCHAR ADC[MAX_PATH + 1]= { L'\0' };
  1779. WCHAR BDC[MAX_PATH + 1]= { L'\0' }; // BDC means just DC for machine B and NOT B(ackup) DC !!!...
  1780. WCHAR Xbuf[MAX_PATH + 1]= { L'\0' }; // general purpose buffer
  1781. WCHAR Ybuf[MAX_PATH + 1]= { L'\0' }; // general purpose buffer
  1782. INT i,j;
  1783. BOOLEAN List=FALSE;
  1784. BOOLEAN Both = FALSE, DirIn=FALSE, DirOut=FALSE;
  1785. BOOLEAN LocalOnly = FALSE, Untrust = FALSE, Downlevel = FALSE, Parent = FALSE;
  1786. BOOLEAN Check=FALSE;
  1787. BOOLEAN Mit = FALSE;
  1788. BOOLEAN LocalCreated = FALSE;
  1789. BOOL Verify = FALSE;
  1790. // BOOLEAN Force = FALSE; moved global
  1791. // BOOLEAN Nt4 = FALSE; this is global
  1792. // BOOLEAN Dbg = FALSE; this is global
  1793. DWORD DirectionLocal=0, DirectionRemote=0;
  1794. WCHAR PasswordBuff[1024];
  1795. PWSTR Password = NULL;
  1796. TD_DOM_INFO Local={0},
  1797. Remote={0};
  1798. LSA_UNICODE_STRING uDomNameL,uDomNameR;
  1799. // help requested? display it and exit ...
  1800. if ( argc<2 ||
  1801. _stricmp( argv[1], "-?") == 0 ||
  1802. _stricmp( argv[1], "/?") == 0 ) {
  1803. Usage();
  1804. goto Done;
  1805. }
  1806. hInst=GetModuleHandle(NULL);
  1807. RtlZeroMemory( &Local, sizeof( TD_DOM_INFO ) );
  1808. RtlZeroMemory( &Remote, sizeof (TD_DOM_INFO ) );
  1809. if(!process_opt(argc,argv, opt_arg)) {
  1810. Status = STATUS_INVALID_PARAMETER;
  1811. Usage();
  1812. goto Done;
  1813. }
  1814. BOOL_ARG(opt_arg,A_LIST, List );
  1815. BOOL_ARG(opt_arg,A_BOTH, Both );
  1816. BOOL_ARG(opt_arg,A_IN, DirIn );
  1817. BOOL_ARG(opt_arg,A_OUT, DirOut );
  1818. BOOL_ARG(opt_arg,A_UNTRUST, Untrust );
  1819. BOOL_ARG(opt_arg,A_CHECK, Check );
  1820. BOOL_ARG(opt_arg,A_VERIFY, Verify );
  1821. BOOL_ARG(opt_arg,A_LOCALONLY,LocalOnly );
  1822. BOOL_ARG(opt_arg,A_DOWNLEVEL,Downlevel );
  1823. BOOL_ARG(opt_arg,A_MIT, Mit );
  1824. BOOL_ARG(opt_arg,A_PARENT, Parent );
  1825. BOOL_ARG(opt_arg,A_DEBUG, Dbg );
  1826. BOOL_ARG(opt_arg,A_FORCE, Force );
  1827. BOOL_ARG(opt_arg,A_NT4, Nt4 );
  1828. BOOL_ARG(opt_arg,A_SIDLIST, SidList );
  1829. //put this after Dbg variable is set
  1830. if(Dbg)
  1831. printf("TRUSTDOM - (ver %ws)\n",VER_FILEVERSION_LSTR);
  1832. //get password (if any)
  1833. if(opt_arg[A_PW].s)
  1834. mbstowcs( PasswordBuff, opt_arg[A_PW].s, strlen( opt_arg[A_PW].s )+1 );
  1835. else PasswordBuff[0]='\0';
  1836. // process normal command line arguments (positional)
  1837. for (j=0,i=1; i<argc; i++) {
  1838. if (!(argv[i][0]=='/' || argv[i][0]=='-')) {
  1839. switch(j) {
  1840. case 0:
  1841. { WCHAR *pws;
  1842. mbstowcs(ADomain, argv[i], strlen(argv[i]) + 1 );
  1843. if((pws=wcschr(ADomain,L','))!=NULL) {
  1844. *pws=L'\0';
  1845. wcscpy(BDomain,pws+1);
  1846. }
  1847. else {
  1848. wcscpy(BDomain,ADomain);
  1849. ADomain[0]=L'\0';
  1850. }
  1851. }
  1852. break;
  1853. }
  1854. j++;
  1855. }
  1856. }
  1857. ParseForDCName(ADomain,ADC);
  1858. ParseForDCName(BDomain,BDC);
  1859. dbgprintf( (0,IDS_DOMARGUMENTS,ADomain,ADC[0]?L":":L"",ADC,BDomain,BDC[0]?L":":L"",BDC) );
  1860. resprintf(2,IDS_WARNING);
  1861. wcsncpy(Xbuf,outbuf,MAX_PATH);
  1862. resprintf(2,IDS_ERROR);
  1863. wcsncpy(Ybuf,outbuf,MAX_PATH);
  1864. //Parameter adjust
  1865. if(SidList)
  1866. List=TRUE;
  1867. //Domain names check:
  1868. { WCHAR *s=NULL;
  1869. BOOL ba, bb;
  1870. if( !(ba=ValidateDomain(s=ADomain)) ||
  1871. !(bb=ValidateDomain(s=BDomain))) {
  1872. resprintf(0,IDS_INVALID_DOMAIN_NAME,s);
  1873. Status = STATUS_INVALID_PARAMETER;
  1874. goto Done;
  1875. }
  1876. }
  1877. // Parameter constraints:
  1878. // '-parent' REQUIRES '-both'
  1879. if (Parent && !Both) {
  1880. if(!Force)
  1881. Status = STATUS_INVALID_PARAMETER;
  1882. resprintf(0,IDS_PARENT_REQ_BOTH,(Force?Xbuf:Ybuf));
  1883. }
  1884. // MIT trusts are always local only
  1885. if (Mit && (!LocalOnly || !Both)) {
  1886. resprintf(0,IDS_MIT_LOCAL_ONLY_BOTH);
  1887. LocalOnly = TRUE;
  1888. Both = TRUE;
  1889. }
  1890. //
  1891. // Validate the parameters
  1892. //
  1893. //specifying both in and out means, yes, '-both'...
  1894. if(DirIn && DirOut)
  1895. Both=TRUE;
  1896. if(List && Mit)
  1897. Status = STATUS_INVALID_PARAMETER;
  1898. if((!List && BDomain[0]==L'\0') || (List && ADomain[0]!=L'\0'))
  1899. Status = STATUS_INVALID_PARAMETER;
  1900. if ( Untrust == TRUE && (Downlevel)) // || Mit || Both ) ) // changed from Both || LocalOnly ||...
  1901. Status = STATUS_INVALID_PARAMETER;
  1902. // if(LocalOnly == TRUE && Both == FALSE)
  1903. // Status = STATUS_INVALID_PARAMETER;;
  1904. if (Mit && (Downlevel || Parent ))
  1905. Status = STATUS_INVALID_PARAMETER;
  1906. // end validating parameters
  1907. if( Status == STATUS_INVALID_PARAMETER ) {
  1908. Usage();
  1909. goto Done;
  1910. }
  1911. if(!Untrust && !List && !Verify) { //check password... otherwise ignore
  1912. if(wcscmp(PasswordBuff,L"*")==0)
  1913. GetPassword(PasswordBuff,1024);
  1914. Password = PasswordBuff;
  1915. }
  1916. ////////////////////////////////////////////////////////////////////////////////
  1917. // list || verify operation: simplified GetDomainInfo scenario...
  1918. ////////////////////////////////////////////////////////////////////////////////
  1919. if ( List ) {
  1920. ULONG i;
  1921. Status = GetDomainInfoForDomain((BDomain[0]==L'\0'?NULL:BDomain),BDC,&Remote, Mit );
  1922. if (!NT_SUCCESS( Status ) )
  1923. goto Done;
  1924. Status = GetTrustLinks( &Remote );
  1925. if (Status!=STATUS_NO_MORE_ENTRIES && !NT_SUCCESS( Status ) )
  1926. goto Done;
  1927. Status = PrintTrustLinks( &Remote );
  1928. goto Done;
  1929. } else
  1930. ////////////////////////////////////////////////////////////////////////////////
  1931. // verify operation
  1932. ////////////////////////////////////////////////////////////////////////////////
  1933. if ( Verify ) {
  1934. Status = VerifyTrusts( BDomain[ 0 ]==L'\0' ? NULL : BDomain, BDC );
  1935. goto Done;
  1936. }
  1937. // regular operation: create/delete trust...
  1938. // get info about the domain(s) involved...
  1939. Status = GetDomainInfoForDomain((ADomain[0]==L'\0'?NULL:ADomain), ADC, &Local, FALSE );
  1940. if ( !NT_SUCCESS( Status ) )
  1941. goto Done;
  1942. Status = GetDomainInfoForDomain( BDomain, BDC, &Remote, Mit );
  1943. if ( !NT_SUCCESS( Status ) ) {
  1944. if(Mit) { //assuming a Unix machine...
  1945. dbgprintf( (0,IDS_DSGETDCNAME_MIT, BDomain) );
  1946. }
  1947. else {
  1948. if(!( Force
  1949. //&& (Status==STATUS_NO_SUCH_DOMAIN)
  1950. //&& LocalOnly && Untrust
  1951. )) // if -force not specified...
  1952. // continue anyway
  1953. goto Done;
  1954. }
  1955. }
  1956. //
  1957. // Ok, now check or or delete or create the trust objects...
  1958. //
  1959. ////////////////////////////////////////////////////////////////////////////////
  1960. // check trust link
  1961. ////////////////////////////////////////////////////////////////////////////////
  1962. if ( Check ) {
  1963. dbgprintf( (0, IDS_PROCESSDOM, GetName(&Local)) );
  1964. Status = CheckTrustLink( &Local, &Remote );
  1965. if (Status!=NERR_Success)
  1966. dbgprintf( (0,IDS_LOCAL_CHK_TRUST_F,Status) );
  1967. if ( !LocalOnly ) {
  1968. dbgprintf( (0, IDS_PROCESSDOM, GetName(&Remote)) );
  1969. Status = CheckTrustLink( &Remote, &Local );
  1970. if (Status!=NERR_Success)
  1971. dbgprintf( (IDS_REMOTE_CHK_TRUST_F,Status) );
  1972. }
  1973. // end check block...
  1974. } else
  1975. ////////////////////////////////////////////////////////////////////////////////
  1976. // delete trust object
  1977. ////////////////////////////////////////////////////////////////////////////////
  1978. if ( Untrust ) {
  1979. dbgprintf( (0, IDS_PROCESSDOM, GetName(&Local)) );
  1980. Status = DeleteTrustLink( &Local, &Remote );
  1981. if (Status!=NERR_Success)
  1982. dbgprintf( (0,IDS_LOCAL_DEL_TRUST_F,Status) );
  1983. if ( !LocalOnly ) {
  1984. dbgprintf( (0, IDS_PROCESSDOM, GetName(&Remote)) );
  1985. Status = DeleteTrustLink( &Remote, &Local );
  1986. if (Status!=NERR_Success)
  1987. dbgprintf( (IDS_REMOTE_DEL_TRUST_F,Status) );
  1988. }
  1989. // end untrust block...
  1990. } else {
  1991. ////////////////////////////////////////////////////////////////////////////
  1992. // create trust links
  1993. ////////////////////////////////////////////////////////////////////////////
  1994. if ( Password == NULL ) {
  1995. Password = L""; // no password specified? then use void password: ""
  1996. }
  1997. if((Local.majver==4 || Remote.majver==4) && !Downlevel) {
  1998. if(!Force)
  1999. Status = STATUS_INVALID_PARAMETER;
  2000. resprintf(0,IDS_NT4_REQ_DOWNLEVEL,(Force?Xbuf:Ybuf));
  2001. if(!NT_SUCCESS(Status))
  2002. goto Done;
  2003. }
  2004. //compute direction of trust based on the values of Both, DirIn, DirOut
  2005. //'Both' has higher priority
  2006. if(Both) {
  2007. DirectionLocal=DirectionRemote=TRUST_DIRECTION_BIDIRECTIONAL;
  2008. } else {
  2009. //default is 'OUTBOUND'... as being DirIn==FALSE and DirOut==TRUE
  2010. DirectionLocal =(DirIn?TRUST_DIRECTION_INBOUND:TRUST_DIRECTION_OUTBOUND);
  2011. DirectionRemote =(DirIn?TRUST_DIRECTION_OUTBOUND:TRUST_DIRECTION_INBOUND);
  2012. }
  2013. swprintf(Xbuf,L"%wZ",GetName(&Local));
  2014. swprintf(Ybuf,L"%wZ",GetName(&Remote));
  2015. //RtlCopyUnicodeString(&uDomNameL,GetName(&Local));
  2016. //RtlCopyUnicodeString(&uDomNameR,GetName(&Remote));
  2017. dbgprintf( (0, IDS_PROCESSDOM, GetName(&Local)) );
  2018. StatusL = CreateTrustLink( &Local, &Remote,
  2019. Password,
  2020. Downlevel,
  2021. Mit,
  2022. Parent,
  2023. DirectionLocal //Both ? TRUST_DIRECTION_BIDIRECTIONAL :
  2024. // TRUST_DIRECTION_OUTBOUND
  2025. );
  2026. if (!NT_SUCCESS(StatusL))
  2027. dbgprintf( (0,IDS_CREATE_TRUST_F, Xbuf,Ybuf,StatusL) );
  2028. //if ( NT_SUCCESS( StatusL ) ) { not needed...
  2029. // LocalCreated = TRUE;
  2030. //}
  2031. if ( NT_SUCCESS( StatusL ) && !LocalOnly ) {
  2032. dbgprintf( (0, IDS_PROCESSDOM, GetName(&Remote)) );
  2033. StatusR = CreateTrustLink( &Remote, &Local,
  2034. Password,
  2035. Downlevel,
  2036. Mit,
  2037. FALSE,
  2038. DirectionRemote //Both ? TRUST_DIRECTION_BIDIRECTIONAL :
  2039. // TRUST_DIRECTION_INBOUND
  2040. );
  2041. if (!NT_SUCCESS(StatusR))
  2042. dbgprintf( (0,IDS_CREATE_TRUST_F, Ybuf,Xbuf, StatusR) );
  2043. }
  2044. if ( !NT_SUCCESS( StatusR ) && NT_SUCCESS( StatusL ) ) { //LocalCreated not used anymore....
  2045. DeleteTrustLink( &Local, &Remote );
  2046. }
  2047. }
  2048. Status = StatusL;
  2049. if( NT_SUCCESS(Status) ) //maybe the 'Remote' attempt failed ?...
  2050. Status = StatusR;
  2051. Done:
  2052. FreeDomainInfo( &Local );
  2053. FreeDomainInfo( &Remote );
  2054. if( NT_SUCCESS( Status ) ) {
  2055. //No message; in this way will be easier also to get a count of the trust links for a list:
  2056. // by example, 'trustdom <dom> -list | findstr ",B," | wc' will get a count of the
  2057. // bidirectional trusts of domain <dom>
  2058. //printf("The command completed successfully\n");
  2059. } else {
  2060. resprintf(0,IDS_COMMAND_FAILED, Status );
  2061. }
  2062. // return 0 for SUCCESS and 1 for some error
  2063. return( !NT_SUCCESS( Status ) );
  2064. }