home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / winbase / security / winnt / domtrust / domtrust.c next >
C/C++ Source or Header  |  1997-10-05  |  24KB  |  854 lines

  1. /*++
  2.  
  3. Copyright 1996 - 1997 Microsoft Corporation
  4.  
  5. Module Name:
  6.  
  7.     domtrust.c
  8.  
  9. Abstract:
  10.  
  11.     This sample illustrates how to manage Windows NT trusted domains at the
  12.     domain controller level.
  13.  
  14.     The first command line argument indicates the name of the new or existing
  15.     trusted domain to create or modify.
  16.  
  17.     The second command line argument indicates the new password for the
  18.     trusted domain specified in the first argument.
  19.  
  20.     The optional third argument indicates the domain name that is the target
  21.     of the trusted domain update operation. If this argument is not specified,
  22.     the update will occur on the local domain. Note that this sample will not
  23.     allow a trusted domain update to occur on a non-domain controller.
  24.  
  25.     This sample works correctly compiled ANSI or Unicode. Note that LAN
  26.     Manager NetXxx API are Unicode only, and Windows NT LSA API are Unicode
  27.     only.
  28.  
  29. Author:
  30.  
  31.     Scott Field (sfield)    05-Feb-96
  32.  
  33. --*/
  34.  
  35. #ifndef UNICODE
  36. #define UNICODE
  37. #define _UNICODE
  38. #endif
  39.  
  40. #include <windows.h>
  41. #include <lm.h>         // for NetXxx API
  42.  
  43. #include "ntsecapi.h"   // \mstools\samples\win32\winnt\security\include\ntsecapi.h
  44.  
  45. #include <stdio.h>
  46.  
  47. void
  48. InitLsaString(
  49.     PLSA_UNICODE_STRING LsaString,
  50.     LPWSTR String
  51.     );
  52.  
  53. NTSTATUS
  54. OpenPolicy(
  55.     LPWSTR ServerName,
  56.     DWORD DesiredAccess,
  57.     PLSA_HANDLE PolicyHandle
  58.     );
  59.  
  60. BOOL
  61. GetDomainSid(
  62.     LPWSTR DomainName,  // domain name to acquire Sid of
  63.     PSID *pDomainSid    // points to allocated Sid on success
  64.     );
  65.  
  66. NTSTATUS
  67. SetTrustedDomainInfo(
  68.     LSA_HANDLE PolicyHandle,
  69.     PSID DomainSid,             // Sid of domain to manipulate
  70.     LPWSTR TrustedDomainName,   // trusted domain name to add/update
  71.     LPWSTR Password             // new trust password for trusted domain
  72.     );
  73.  
  74. BOOL
  75. VerifyTrustRelationship(
  76.     LPWSTR TargetDomainName,        // domain name to verify trust at
  77.     LPWSTR TrustAccountToVerify,    // trusted domain name to verify
  78.     LPWSTR Password,                // password associated with trust
  79.     LPBOOL bTrustVerified           // indicates if trust was verified
  80.     );
  81.  
  82. void
  83. DisplayNtStatus(
  84.     LPSTR szAPI,    // ANSI string containing API name
  85.     NTSTATUS Status
  86.     );
  87.  
  88. void
  89. DisplayError(
  90.     LPSTR szAPI,    // pointer to failed API name
  91.     DWORD dwLastError
  92.     );
  93.  
  94. #define RTN_OK 0
  95. #define RTN_USAGE 1
  96. #define RTN_ERROR 13
  97.  
  98. //
  99. // if you have the DDK, include Ntstatus.h
  100. //
  101. #ifndef STATUS_SUCCESS
  102. #define STATUS_SUCCESS                  ((NTSTATUS)0x00000000L)
  103. #define STATUS_OBJECT_NAME_NOT_FOUND    ((NTSTATUS)0xC0000034L)
  104. #define STATUS_INVALID_SID              ((NTSTATUS)0xC0000078L)
  105. #endif
  106.  
  107. //
  108. // Unicode entry point and argv
  109. //
  110.  
  111. int
  112. __cdecl
  113. wmain(
  114.     int argc,
  115.     wchar_t *argv[]
  116.     )
  117. {
  118.     BOOL bAllocTargetDomain;    // did you allocate memory for target?
  119.     LSA_HANDLE PolicyHandle;
  120.     LPWSTR TargetDomainName;    // target domain of policy update
  121.     LPWSTR DomainController;    // computer name where policy update
  122.     PSID DomainSid; // allocated Sid representing domain to trust
  123.     LPWSTR TrustedDomainName;
  124.     LPWSTR Password;
  125.     BOOL bTrustVerified;
  126.     NET_API_STATUS nas;
  127.     NTSTATUS Status;
  128.  
  129.     if(argc < 3) {
  130.         fprintf(stderr,
  131.             "Usage: %ls <NewTrustedDomain> <Password> [TargetDomain]\n",
  132.             argv[0]);
  133.         return RTN_USAGE;
  134.     }
  135.  
  136.     TrustedDomainName = argv[1];    // existing or new TrustedDomain
  137.     Password = argv[2];             // new password for TrustedDomain
  138.  
  139.     //
  140.     // if a TargetDomain was specified, point to that.
  141.     // if not, set TargetDomain to the current domain if a DC.
  142.     //
  143.     if(argc == 4 && *argv[3] != L'\0') {
  144.         TargetDomainName = argv[3]; // domain to update trust at
  145.         bAllocTargetDomain = FALSE; // no memory allocated
  146.     }
  147.     else {
  148.         PSERVER_INFO_101 si101;
  149.         DWORD Type;
  150.         PUSER_MODALS_INFO_2 umi2;
  151.  
  152.         //
  153.         // ensure that the local computer is a DC. This operation is only
  154.         // appropriate against a domain controller.
  155.         //
  156.         nas = NetServerGetInfo(NULL, 101, (LPBYTE *)&si101);
  157.         if(nas != NERR_Success) {
  158.             DisplayError("NetServerGetInfo", nas);
  159.             return RTN_ERROR;
  160.         }
  161.  
  162.         Type = si101->sv101_type;
  163.         NetApiBufferFree(si101);
  164.  
  165.         if( !(Type & SV_TYPE_DOMAIN_CTRL) &&
  166.             !(Type & SV_TYPE_DOMAIN_BAKCTRL) ) {
  167.             printf("Error:  Specify a TargetDomain; this operation"
  168.                     " is only valid against a domain.\n");
  169.             return RTN_ERROR;
  170.         }
  171.  
  172.         //
  173.         // obtain the local computer's domain name
  174.         //
  175.         nas = NetUserModalsGet(NULL, 2, (LPBYTE *)&umi2);
  176.  
  177.         if(nas != NERR_Success) {
  178.             DisplayError("NetUserModalsGet", nas);
  179.             return RTN_ERROR;
  180.         }
  181.  
  182.         //
  183.         // copy the domain name to new storage
  184.         //
  185.         TargetDomainName = (LPWSTR)HeapAlloc(GetProcessHeap(), 0,
  186.             (lstrlenW(umi2->usrmod2_domain_name) + 1) * sizeof(WCHAR));
  187.  
  188.         if(TargetDomainName != NULL) {
  189.             lstrcpyW(TargetDomainName, umi2->usrmod2_domain_name);
  190.             bAllocTargetDomain = TRUE; // we allocated memory
  191.         }
  192.  
  193.         NetApiBufferFree(umi2); // free memory allocated by NetXxx
  194.  
  195.         //
  196.         // if an error occurred allocating memory, exit
  197.         //
  198.         if(TargetDomainName == NULL) {
  199.             DisplayError("HeapAlloc", 0);
  200.             return RTN_ERROR;
  201.         }
  202.     }
  203.  
  204.     //
  205.     // do not allow a Domain to trust itself
  206.     //
  207.     if(lstrcmpiW(TargetDomainName, TrustedDomainName) == 0) {
  208.         fprintf(stderr,"Error:  Domain %ls cannot trust itself.\n",
  209.             TargetDomainName);
  210.  
  211.         return RTN_ERROR;
  212.     }
  213.  
  214.     //
  215.     // ensure Password and TrustedDomainName are the correct length
  216.     //
  217.     if(lstrlenW(Password) > LM20_PWLEN)
  218.         Password[LM20_PWLEN] = L'\0'; // truncate
  219.  
  220.     if(lstrlenW(TrustedDomainName) > MAX_COMPUTERNAME_LENGTH)
  221.         TrustedDomainName[MAX_COMPUTERNAME_LENGTH] = L'\0'; // truncate
  222.  
  223.     //
  224.     // obtain the primary DC computer name from the specified
  225.     // TargetDomainName
  226.     //
  227.     nas = NetGetDCName(
  228.         NULL, TargetDomainName, (LPBYTE *)&DomainController);
  229.  
  230.     if(nas != NERR_Success) {
  231.         DisplayError("NetGetDCName", nas);
  232.         return RTN_ERROR;
  233.     }
  234.  
  235.     //
  236.     // verify the trust relationship
  237.     //
  238.     if(!VerifyTrustRelationship(
  239.         TrustedDomainName,
  240.         TargetDomainName,   // trust account to verify
  241.         Password,
  242.         &bTrustVerified
  243.         )) {
  244.         //
  245.         // an error occurred during trust relationship verification
  246.         //
  247.         DisplayError("VerifyTrustRelationship", GetLastError());
  248.     }
  249.     else {
  250.         //
  251.         // inform the user if the trust was not verified
  252.         //
  253.         if(!bTrustVerified) {
  254.             DWORD dwTrustVerifyFailReason = GetLastError();
  255.  
  256.             //
  257.             // You could exit here, but this is optional. Reasons for
  258.             // trust verification failure could be non-existent
  259.             // "permitted to trust" on the verified domain (rc=1317),
  260.             // wrong password (rc=1326), etc
  261.             //
  262.             printf("Warning:  ");
  263.  
  264.             switch(dwTrustVerifyFailReason) {
  265.                 case ERROR_NO_SUCH_USER:
  266.                     printf("%ls not permitted-to-trust on %ls\n",
  267.                         TargetDomainName, TrustedDomainName);
  268.                     break;
  269.  
  270.                 case ERROR_LOGON_FAILURE:
  271.                     printf("Trust %ls has incorrect password on %ls\n",
  272.                         TrustedDomainName, TargetDomainName);
  273.                     break;
  274.  
  275.                 default:
  276.                     DisplayError("Trust was not verified.  Non-fatal",
  277.                         dwTrustVerifyFailReason);
  278.             } // switch
  279.         }
  280.     }
  281.  
  282.     //
  283.     // fetch the DomainSid of the domain to trust
  284.     //
  285.     if(!GetDomainSid(TrustedDomainName, &DomainSid)) {
  286.         DisplayError("GetDomainSid", GetLastError());
  287.         return RTN_ERROR;
  288.     }
  289.  
  290.     //
  291.     // open the policy on the target domain
  292.     //
  293.     Status = OpenPolicy(
  294.                 DomainController,
  295.                 POLICY_CREATE_SECRET |  // for password set operation
  296.                 POLICY_TRUST_ADMIN,     // for trust creation
  297.                 &PolicyHandle
  298.                 );
  299.  
  300.     if(Status != STATUS_SUCCESS) {
  301.         DisplayNtStatus("OpenPolicy", Status);
  302.         return RTN_ERROR;
  303.     }
  304.  
  305.     //
  306.     // Update TrustedDomainInfo to reflect the specified trust.
  307.     //
  308.     Status = SetTrustedDomainInfo(
  309.         PolicyHandle,
  310.         DomainSid,
  311.         TrustedDomainName,
  312.         Password
  313.         );
  314.  
  315.     if(Status != STATUS_SUCCESS) {
  316.         DisplayNtStatus("SetTrustedDomainInfo", Status);
  317.         return RTN_ERROR;
  318.     }
  319.  
  320.     //
  321.     // if you allocated memory for TargetDomainName, free it
  322.     //
  323.     if(bAllocTargetDomain)
  324.         HeapFree(GetProcessHeap(), 0, TargetDomainName);
  325.  
  326.     //
  327.     // free the Sid which was allocated for the TrustedDomain Sid
  328.     //
  329.     FreeSid(DomainSid);
  330.  
  331.     //
  332.     // close the policy handle
  333.     //
  334.     LsaClose(PolicyHandle);
  335.  
  336.     if(DomainController != NULL)
  337.         NetApiBufferFree(DomainController);
  338.  
  339.     return RTN_OK;
  340. }
  341.  
  342. void
  343. InitLsaString(
  344.     PLSA_UNICODE_STRING LsaString,
  345.     LPWSTR String
  346.     )
  347. {
  348.     DWORD StringLength;
  349.  
  350.     if(String == NULL) {
  351.         LsaString->Buffer = NULL;
  352.         LsaString->Length = 0;
  353.         LsaString->MaximumLength = 0;
  354.  
  355.         return;
  356.     }
  357.  
  358.     StringLength = lstrlenW(String);
  359.     LsaString->Buffer = String;
  360.     LsaString->Length = (USHORT) StringLength * sizeof(WCHAR);
  361.     LsaString->MaximumLength = (USHORT) (StringLength + 1) *
  362.         sizeof(WCHAR);
  363. }
  364.  
  365. NTSTATUS
  366. OpenPolicy(
  367.     LPWSTR ServerName,
  368.     DWORD DesiredAccess,
  369.     PLSA_HANDLE PolicyHandle
  370.     )
  371. {
  372.     LSA_OBJECT_ATTRIBUTES ObjectAttributes;
  373.     LSA_UNICODE_STRING ServerString;
  374.     PLSA_UNICODE_STRING Server;
  375.  
  376.     //
  377.     // Always initialize the object attributes to all zeroes
  378.     //
  379.     ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
  380.  
  381.     if(ServerName != NULL) {
  382.         //
  383.         // Make a LSA_UNICODE_STRING out of the LPWSTR passed in
  384.         //
  385.         InitLsaString(&ServerString, ServerName);
  386.  
  387.         Server = &ServerString;
  388.     } else {
  389.         Server = NULL;
  390.     }
  391.  
  392.     //
  393.     // Attempt to open the policy
  394.     //
  395.     return LsaOpenPolicy(
  396.                 Server,
  397.                 &ObjectAttributes,
  398.                 DesiredAccess,
  399.                 PolicyHandle
  400.                 );
  401. }
  402.  
  403. /*++
  404.  This function retrieves the Sid representing the specified DomainName.
  405.  
  406.  If the function succeeds, the return value is TRUE and pDomainSid will
  407.  point to the Sid representing the specified DomainName. The caller
  408.  should free the memory associated with this Sid with the Win32 API
  409.  FreeSid() when the Sid is no longer needed.
  410.  
  411.  If the function fails, the return value is FALSE, and pDomainSid will
  412.  be set to NULL.
  413.  
  414. --*/
  415.  
  416. BOOL
  417. GetDomainSid(
  418.     LPWSTR DomainName,  // domain name to acquire Sid of
  419.     PSID *pDomainSid    // points to allocated Sid on success
  420.     )
  421. {
  422.     NET_API_STATUS nas;
  423.     LPWSTR DomainController;
  424.     PUSER_MODALS_INFO_2 umi2 = NULL;
  425.     DWORD dwSidSize;
  426.     BOOL bSuccess = FALSE; // assume this function will fail
  427.  
  428.     *pDomainSid = NULL; // invalidate pointer
  429.  
  430.     //
  431.     // obtain the PDC computer name of the supplied domain name
  432.     //
  433.     nas = NetGetDCName(NULL, DomainName, (LPBYTE *)&DomainController);
  434.     if(nas != NERR_Success) {
  435.         SetLastError(nas);
  436.         return FALSE;
  437.     }
  438.  
  439.     __try {
  440.  
  441.     //
  442.     // obtain the domain Sid from the PDC
  443.     // NOTE: this may fail if the credentials of the caller are not
  444.     // recognized or valid on the target computer. In this case, it
  445.     // is necessary to first establish a connection via NetUseAdd()
  446.     // at info-level 2 to the remote IPC$, specifying EMPTY
  447.     // credentials.
  448.     //
  449.     nas = NetUserModalsGet(DomainController, 2, (LPBYTE *)&umi2);
  450.     if(nas != NERR_Success) __leave;
  451.  
  452.     //
  453.     // if the Sid is valid, obtain the size of the Sid
  454.     //
  455.     if(!IsValidSid(umi2->usrmod2_domain_id)) __leave;
  456.     dwSidSize = GetLengthSid(umi2->usrmod2_domain_id);
  457.  
  458.     //
  459.     // allocate storage and copy the Sid
  460.     //
  461.     *pDomainSid = (PSID)HeapAlloc(GetProcessHeap(), 0, dwSidSize);
  462.     if(*pDomainSid == NULL) __leave;
  463.  
  464.     if(!CopySid(dwSidSize, *pDomainSid, umi2->usrmod2_domain_id))
  465.         __leave;
  466.  
  467.     bSuccess = TRUE; // indicate success
  468.  
  469.     } // try
  470.     __finally {
  471.  
  472.     //
  473.     // free allocated memory
  474.     //
  475.     NetApiBufferFree(DomainController);
  476.  
  477.     if(umi2 != NULL)
  478.         NetApiBufferFree(umi2);
  479.  
  480.     if(!bSuccess) {
  481.         //
  482.         // if the function failed, free memory and indicate result code
  483.         //
  484.  
  485.         if(*pDomainSid != NULL) {
  486.             FreeSid(*pDomainSid);
  487.             *pDomainSid = NULL;
  488.         }
  489.  
  490.         if(nas != NERR_Success) {
  491.             SetLastError(nas);
  492.         }
  493.     }
  494.  
  495.     }
  496.     return bSuccess;
  497. }
  498.  
  499. /*++
  500.  This function manipulates the trust associated with the supplied
  501.  DomainSid.
  502.  
  503.  If the domain trust does not exist, it is created with the
  504.  specified password. In this case, the supplied PolicyHandle must
  505.  have been opened with POLICY_TRUST_ADMIN and POLICY_CREATE_SECRET
  506.  access to the policy object.
  507.  
  508.  If the domain trust exists, the password is updated with the
  509.  password specified by the Password parameter. The trust OldPassword
  510.  is set to the previous password.
  511.  
  512.  If DomainName and Password are NULL, the trusted domain specified by
  513.  DomainSid is deleted.
  514.  
  515. --*/
  516.  
  517. NTSTATUS
  518. SetTrustedDomainInfo(
  519.     LSA_HANDLE PolicyHandle,
  520.     PSID DomainSid,             // Sid of domain to manipulate
  521.     LPWSTR TrustedDomainName,   // trusted domain name to add/update
  522.     LPWSTR Password             // new trust password for trusted domain
  523.     )
  524. {
  525.     PTRUSTED_PASSWORD_INFO tpi;
  526. //    PTRUSTED_DOMAIN_NAME_INFO tdni;
  527.     LSA_UNICODE_STRING LsaPassword;
  528.     TRUSTED_PASSWORD_INFO Newtpi;
  529.     BOOL bTrustExists = TRUE; // assume trust exists
  530.     NTSTATUS Status;
  531.  
  532.     //
  533.     // Make sure you were passed a valid Sid
  534.     //
  535.     if(DomainSid == NULL || !IsValidSid(DomainSid))
  536.         return STATUS_INVALID_SID;
  537.  
  538.     //
  539.     // if TristedDomainName and Password is NULL (or emptry strings),
  540.     // delete the specified trust
  541.     //
  542.     if( (TrustedDomainName == NULL || *TrustedDomainName == L'\0') &&
  543.         (Password == NULL || *Password == L'\0') ) {
  544.         return LsaDeleteTrustedDomain(PolicyHandle, DomainSid);
  545.     }
  546.  
  547.     //
  548.     // query the current password, which is used to update the
  549.     // OldPassword. If the trust doesn't exist, indicate this so that the
  550.     // trust will be created.
  551.     //
  552.     Status = LsaQueryTrustedDomainInfo(
  553.         PolicyHandle,
  554.         DomainSid,
  555.         TrustedPasswordInformation,
  556.         &tpi);
  557.  
  558.     if(Status != STATUS_SUCCESS) {
  559.         if(Status == STATUS_OBJECT_NAME_NOT_FOUND) {
  560.             bTrustExists = FALSE; // indicate trust does not exist
  561.         }
  562.         else {
  563.             DisplayNtStatus("LsaQueryTrustedDomainInfo", Status);
  564.             return Status;
  565.         }
  566.     }
  567.  
  568.     InitLsaString(&LsaPassword, Password);
  569.  
  570.     //
  571.     // set the new password to the supplied password
  572.     //
  573.     Newtpi.Password = LsaPassword;
  574.  
  575.     if(bTrustExists) {
  576.         //
  577.         // if the trust already existed, set OldPassword to the
  578.         // current password...
  579.         //
  580.         Newtpi.OldPassword = tpi->Password;
  581.     }
  582.     else {
  583.         LSA_UNICODE_STRING LsaDomainName;
  584.         DWORD cchDomainName; // number of chars in TrustedDomainName
  585.  
  586.         //
  587.         // if the trust did not exist, set OldPassword to the
  588.         // supplied password...
  589.         //
  590.         Newtpi.OldPassword = LsaPassword;
  591.  
  592.         InitLsaString(&LsaDomainName, TrustedDomainName);
  593.  
  594.         //
  595.         // ...convert TrustedDomainName to uppercase...
  596.         //
  597.         cchDomainName = LsaDomainName.Length / sizeof(WCHAR);
  598.         while(cchDomainName--) {
  599.             LsaDomainName.Buffer[cchDomainName] =
  600.              towupper(LsaDomainName.Buffer[cchDomainName]);
  601.         }
  602.  
  603.         //
  604.         // ...create the trusted domain object
  605.         //
  606.         Status = LsaSetTrustedDomainInformation(
  607.             PolicyHandle,
  608.             DomainSid,
  609.             TrustedDomainNameInformation,
  610.             &LsaDomainName
  611.             );
  612.  
  613.         if(Status != STATUS_SUCCESS) return Status;
  614.     }
  615.  
  616.     //
  617.     // update TrustedPasswordInformation for the specified trust
  618.     //
  619.     Status = LsaSetTrustedDomainInformation(
  620.         PolicyHandle,
  621.         DomainSid,
  622.         TrustedPasswordInformation,
  623.         &Newtpi
  624.         );
  625.  
  626.     //
  627.     // if a trust already existed, free the memory associated with
  628.     // the retrieved information
  629.     //
  630.     if(bTrustExists) LsaFreeMemory(tpi);
  631.  
  632.     return Status;
  633. }
  634.  
  635. /*++
  636.  
  637.  This function verifies that the "permitted to trust" side of the
  638.  trust relationship has been established and that the specified
  639.  password matches the "permitted to trust" password.
  640.  
  641.  If the function fails, the return value is FALSE, and bTrustVerified
  642.  is undefined.
  643.  
  644.  If the function succeeds, the trust verification succeeded, and
  645.  bTrustVerified is set to the result of the verification.
  646.  
  647.  If bTrustVerified is TRUE, the trust relationship is verfied.
  648.  
  649.  If bTrustVerified is FALSE, the trust was not verified.  Call
  650.  GetLastError() to get extended error information.
  651.  
  652.  ERROR_NO_SUCH_USER indicates that the "permitted to trust"
  653.  UF_INTERDOMAIN_TRUST_ACCOUNT does not exist on the specified domain.
  654.  
  655.  ERROR_LOGON_FAILURE indicates that the supplied password does
  656.  not match the password in the "permitted to trust"
  657.  UF_INTERDOMAIN_TRUST_ACCOUNT.
  658.  
  659.  NOTE: if a connection exists to the domain controller of the
  660.  TargetDomainName prior to calling this function, this function will
  661.  fail due to a credential conflict (WinError == 1219).
  662.  
  663. --*/
  664.  
  665. BOOL
  666. VerifyTrustRelationship(
  667.     LPWSTR TargetDomainName,        // domain name to verify trust at
  668.     LPWSTR TrustAccountToVerify,    // trusted domain name to verify
  669.     LPWSTR Password,                // password associated with trust
  670.     LPBOOL bTrustVerified           // indicates if trust was verified
  671.     )
  672. {
  673.     NET_API_STATUS nas;
  674.     USE_INFO_2 ui2;
  675.     LPWSTR DomainController;
  676.     LPWSTR szIpc = L"\\IPC$";
  677.     LPWSTR RemoteResource = NULL;
  678.     LPWSTR UserName = NULL;
  679.     BOOL bSuccess = FALSE; // assume this function will fail
  680.  
  681.     //
  682.     // fetch the computer name of the domain you try to connect to
  683.     //
  684.     nas = NetGetDCName(
  685.         NULL, TargetDomainName, (LPBYTE *)&DomainController);
  686.     if(nas != NERR_Success) {
  687.         SetLastError(nas);
  688.         return FALSE;
  689.     }
  690.  
  691.     __try {
  692.  
  693.     //
  694.     // build the \\<DCName>\ipc$ as the remote resource
  695.     //
  696.     RemoteResource = (LPWSTR)HeapAlloc(GetProcessHeap(), 0,
  697.         (lstrlenW(DomainController) + lstrlenW(szIpc) + 1 ) *
  698.             sizeof(WCHAR)
  699.         );
  700.  
  701.     if(RemoteResource == NULL) __leave;
  702.  
  703.     if(lstrcpyW(RemoteResource, DomainController) == NULL) __leave;
  704.     if(lstrcatW(RemoteResource, szIpc) == NULL) __leave;
  705.  
  706.     //
  707.     // build the user name as <TrustAccountToVerify>$
  708.     //
  709.     UserName = (LPWSTR)HeapAlloc(GetProcessHeap(), 0,
  710.         (lstrlenW(TrustAccountToVerify) + 1 + 1) * sizeof(WCHAR)
  711.         );
  712.  
  713.     if(UserName == NULL) __leave;
  714.  
  715.     if(lstrcpyW(UserName, TrustAccountToVerify) == NULL) __leave;
  716.     if(lstrcatW(UserName, L"$") == NULL) __leave;
  717.  
  718.     ZeroMemory(&ui2, sizeof(ui2));
  719.  
  720.     ui2.ui2_local = NULL;
  721.     ui2.ui2_remote = RemoteResource;
  722.     ui2.ui2_asg_type = USE_IPC;
  723.     ui2.ui2_password = Password;
  724.     ui2.ui2_username = UserName;
  725.     ui2.ui2_domainname = TargetDomainName;
  726.  
  727.     //
  728.     // Attempt to establish a connection to the target domain.
  729.     // If the result is ERROR_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT,
  730.     // this illustrates the supplied Password matches an existing
  731.     // trust account because the credentials were validated but
  732.     // a logon is not allowed for this account type.
  733.     //
  734.     nas = NetUseAdd(NULL, 2, (LPBYTE)&ui2, NULL);
  735.  
  736.     if(nas == ERROR_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT) {
  737.         *bTrustVerified = TRUE;     // indicate trust verified
  738.     }
  739.     else {
  740.         *bTrustVerified = FALSE;    // indicate trust not verified
  741.  
  742.         //
  743.         // if the connection succeeded, the UF_INTERDOMAIN_TRUST_ACCOUNT
  744.         // does not exist, because the supplied credentials aren't
  745.         // recognized by the remote (default credentials are applied).
  746.         // Delete the connection and indicate the "permitted to trust"
  747.         // account is non-existent.
  748.         //
  749.         if(nas == NERR_Success) {
  750.             NetUseDel(NULL, RemoteResource, 0);
  751.             nas = ERROR_NO_SUCH_USER;
  752.         }
  753.     }
  754.  
  755.     bSuccess = TRUE; // indicate this function succeeded
  756.  
  757.     } // try
  758.     __finally {
  759.  
  760.     //
  761.     // free allocated memory
  762.     //
  763.     NetApiBufferFree(DomainController);
  764.  
  765.     if(RemoteResource != NULL) {
  766.         HeapFree(GetProcessHeap(), 0, RemoteResource);
  767.     }
  768.  
  769.     if(UserName != NULL) {
  770.         HeapFree(GetProcessHeap(), 0, UserName);
  771.     }
  772.  
  773.     //
  774.     // if you succeeded, but trust could not be verified, indicate why
  775.     //
  776.     if(bSuccess == TRUE && *bTrustVerified == FALSE) {
  777.         SetLastError(nas);
  778.     }
  779.  
  780.     }
  781.  
  782.     return bSuccess;
  783. }
  784.  
  785. void
  786. DisplayNtStatus(
  787.     LPSTR szAPI,    // ANSI string containing API name
  788.     NTSTATUS Status
  789.     )
  790. {
  791.     //
  792.     // convert the NTSTATUS to Winerror and display the result
  793.     //
  794.     DisplayError(szAPI, LsaNtStatusToWinError(Status));
  795. }
  796.  
  797.  
  798. void
  799. DisplayError(
  800.     LPSTR szAPI,    // pointer to failed API name
  801.     DWORD dwLastError
  802.     )
  803. {
  804.     HMODULE hModule = NULL;
  805.     LPSTR MessageBuffer;
  806.     DWORD dwBufferLength;
  807.  
  808.     fprintf(stderr,"%s error! (rc=%lu)\n", szAPI, dwLastError);
  809.  
  810.     if(dwLastError >= NERR_BASE && dwLastError <= MAX_NERR) {
  811.         hModule = LoadLibraryEx(
  812.             TEXT("netmsg.dll"),
  813.             NULL,
  814.             LOAD_LIBRARY_AS_DATAFILE
  815.             );
  816.     }
  817.  
  818.     if(dwBufferLength=FormatMessageA(
  819.         FORMAT_MESSAGE_ALLOCATE_BUFFER |
  820.         FORMAT_MESSAGE_IGNORE_INSERTS |
  821.         FORMAT_MESSAGE_FROM_SYSTEM |
  822.         ((hModule != NULL) ? FORMAT_MESSAGE_FROM_HMODULE : 0),
  823.         hModule, // module to get message from
  824.         dwLastError,
  825.         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // default language
  826.         (LPSTR) &MessageBuffer,
  827.         0,
  828.         NULL
  829.         ))
  830.     {
  831.         DWORD dwBytesWritten;
  832.  
  833.         //
  834.         // Output message string on stderr
  835.         //
  836.         WriteFile(
  837.             GetStdHandle(STD_ERROR_HANDLE),
  838.             MessageBuffer,
  839.             dwBufferLength,
  840.             &dwBytesWritten,
  841.             NULL
  842.             );
  843.  
  844.         //
  845.         // free the buffer allocated by the system
  846.         //
  847.         LocalFree(MessageBuffer);
  848.     }
  849.  
  850.     if(hModule != NULL)
  851.         FreeLibrary(hModule);
  852. }
  853.  
  854.