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.
 
 
 
 
 
 

1329 lines
42 KiB

// Trust.cpp : Implementation of CTrustMgrApp and DLL registration.
#include "stdafx.h"
//#import "\bin\McsVarSetMin.tlb" no_namespace, named_guids
#import "VarSet.tlb" no_namespace, named_guids rename("property", "aproperty")
#include "TrustMgr.h"
#include "Trust.h"
#include "Common.hpp"
#include "UString.hpp"
#include "ResStr.h"
#include "ErrDct.hpp"
#include "EaLen.hpp"
#include "LSAUtils.h"
#include <lm.h>
#include "GetDcName.h"
#include <iads.h>
#include <adshlp.h>
#include "ntsecapi.h"
#include "SecPI.h"
#include "cipher.hpp"
#ifndef TRUST_ATTRIBUTE_FOREST_TRANSITIVE
#define TRUST_ATTRIBUTE_FOREST_TRANSITIVE 0x00000008 // This link may contain forest trust information
#endif
StringLoader gString;
TErrorDct err;
// This method is called by the dispatcher to verify that this is a valid plug-in
// Only valid plug-ins will be sent out with the agents
// The purpose of this check is to make it more difficult for unauthorized parties
// to use our plug-in interface, since it is currently undocumented.
STDMETHODIMP CTrust::Verify(/*[in,out]*/ULONG * pData,/*[in]*/ULONG size)
{
McsChallenge * pMcsChallenge;
long lTemp1;
long lTemp2;
if( size == sizeof(McsChallenge) )
{
pMcsChallenge = (McsChallenge*)(pData);
SimpleCipher((LPBYTE)pMcsChallenge,size);
pMcsChallenge->MCS[0] = 'M';
pMcsChallenge->MCS[1] = 'C';
pMcsChallenge->MCS[2] = 'S';
pMcsChallenge->MCS[3] = 0;
lTemp1 = pMcsChallenge->lRand1 + pMcsChallenge->lRand2;
lTemp2 = pMcsChallenge->lRand2 - pMcsChallenge->lRand1;
pMcsChallenge->lRand1 = lTemp1;
pMcsChallenge->lRand2 = lTemp2;
pMcsChallenge->lTime += 100;
SimpleCipher((LPBYTE)pMcsChallenge,size);
}
else
return E_FAIL;
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
//
STDMETHODIMP CTrust::QueryTrust(BSTR domTrusting, BSTR domTrusted, IUnknown **pVarSet)
{
HRESULT hr = S_OK;
return hr;
}
STDMETHODIMP CTrust::CreateTrust(BSTR domTrusting, BSTR domTrusted, BOOL bBidirectional, BOOL *pbErrorFromTrusting, BOOL *pbErrorFromTrusted)
{
HRESULT hr = S_OK;
*pbErrorFromTrusting = FALSE;
*pbErrorFromTrusted = FALSE;
hr = CheckAndCreate(domTrusting,domTrusted,NULL,NULL,NULL,NULL,NULL,NULL,TRUE,bBidirectional,pbErrorFromTrusting,pbErrorFromTrusted);
return HRESULT_FROM_WIN32(hr);
}
STDMETHODIMP
CTrust::CreateTrustWithCreds(
BSTR domTrusting,
BSTR domTrusted,
BSTR credTrustingDomain,
BSTR credTrustingAccount,
BSTR credTrustingPassword,
BSTR credTrustedDomain,
BSTR credTrustedAccount,
BSTR credTrustedPassword,
BOOL bBidirectional,
BOOL *pbErrorFromTrusting,
BOOL *pbErrorFromTrusted
)
{
HRESULT hr = S_OK;
*pbErrorFromTrusting = FALSE;
*pbErrorFromTrusted = FALSE;
hr = CheckAndCreate(domTrusting,domTrusted,credTrustingDomain,credTrustingAccount,credTrustingPassword,
credTrustedDomain,credTrustedAccount,credTrustedPassword,TRUE,bBidirectional,
pbErrorFromTrusting,pbErrorFromTrusted);
return hr;
}
STDMETHODIMP CTrust::GetRegisterableFiles(/* [out] */SAFEARRAY ** pArray)
{
SAFEARRAYBOUND bound[1] = { 0, 0 };
// this plug-in runs locally, no files to distribute
(*pArray) = SafeArrayCreate(VT_BSTR,1,bound);
return S_OK;
}
STDMETHODIMP CTrust::GetRequiredFiles(/* [out] */SAFEARRAY ** pArray)
{
SAFEARRAYBOUND bound[1] = { 0, 0 };
// this plug-in runs locally, no files to distribute
(*pArray) = SafeArrayCreate(VT_BSTR,1,bound);
return S_OK;
}
STDMETHODIMP CTrust::GetDescription(/* [out] */ BSTR * description)
{
(*description) = SysAllocString(L"Sets up needed trusts between domains.");
return S_OK;
}
BOOL IsDownLevel(WCHAR * sComputer)
{
BOOL bDownlevel = TRUE;
WKSTA_INFO_100 * pInfo;
long rc = NetWkstaGetInfo(sComputer,100,(LPBYTE*)&pInfo);
if ( ! rc )
{
if ( pInfo->wki100_ver_major >= 5 )
{
bDownlevel = FALSE;
}
NetApiBufferFree(pInfo);
}
return bDownlevel;
}
// Helper function that finds a trusts in our varset list
LONG CTrust::FindInboundTrust(IVarSet * pVarSet,WCHAR * sName,LONG max)
{
LONG ndx = -1;
LONG curr = 0;
WCHAR key[100];
_bstr_t tName;
for ( curr = 0 ; curr < max ; curr++ )
{
swprintf(key,L"Trusts.%ld",curr);
tName = pVarSet->get(key);
if ( ! UStrICmp(tName,sName) )
{
// found it!
ndx = curr;
break;
}
}
return ndx;
}
HRESULT
CTrust::CheckAndCreateTrustingSide(
LSA_HANDLE hTrusting,
WCHAR * trustingDomain,
WCHAR * trustedDomain,
WCHAR * trustingComp,
WCHAR * trustedComp,
WCHAR * trustedDNSName,
BYTE * trustedSid,
BOOL bCreate,
BOOL bBidirectional,
BOOL bDownLevel,
BOOL * pbErrorFromTrusting,
BOOL * pbErrorFromTrusted
)
{
DWORD rc = S_OK;
// if credentials are specified, use them
NTSTATUS status;
LSA_AUTH_INFORMATION curr;
LSA_AUTH_INFORMATION prev;
WCHAR password[] = L"password";
if ( bCreate )
{
// set up the auth information for the trust relationship
curr.AuthInfo = (LPBYTE)password;
curr.AuthInfoLength = UStrLen(password) * sizeof(WCHAR);
curr.AuthType = TRUST_AUTH_TYPE_CLEAR;
curr.LastUpdateTime.QuadPart = 0;
prev.AuthInfo = (LPBYTE)password;
prev.AuthInfoLength = UStrLen(password) * sizeof(WCHAR);
prev.AuthType = TRUST_AUTH_TYPE_CLEAR;
prev.LastUpdateTime.QuadPart = 0;
// set up the trusting side of the relationship
if ( IsDownLevel(trustingComp) )
{
TRUSTED_DOMAIN_NAME_INFO nameInfo;
InitLsaString(&nameInfo.Name,const_cast<WCHAR*>(trustedDomain));
status = LsaSetTrustedDomainInformation(hTrusting,trustedSid,TrustedDomainNameInformation,&nameInfo);
rc = LsaNtStatusToWinError(status);
if ( ! rc || rc == ERROR_ALREADY_EXISTS )
{
// set the password for the new trust
TRUSTED_PASSWORD_INFO pwdInfo;
InitLsaString(&pwdInfo.Password,password);
InitLsaString(&pwdInfo.OldPassword,NULL);
status = LsaSetTrustedDomainInformation(hTrusting,trustedSid,TrustedPasswordInformation,&pwdInfo);
rc = LsaNtStatusToWinError(status);
}
}
else
{
// for Win2K domain, use LsaCreateTrustedDomainEx
// to create the trustedDomain object.
LSA_UNICODE_STRING sTemp;
TRUSTED_DOMAIN_INFORMATION_EX trustedInfo;
TRUSTED_DOMAIN_AUTH_INFORMATION trustAuth;
InitLsaString(&sTemp, const_cast<WCHAR*>(trustedDomain));
trustedInfo.FlatName = sTemp;
if (bDownLevel)
InitLsaString(&sTemp, trustedDomain);
else
InitLsaString(&sTemp, trustedDNSName);
trustedInfo.Name = sTemp;
trustedInfo.Sid = trustedSid;
if (bDownLevel)
{
trustedInfo.TrustType = TRUST_TYPE_DOWNLEVEL;
}
else
{
trustedInfo.TrustType = TRUST_TYPE_UPLEVEL;
}
if ( bBidirectional )
trustedInfo.TrustDirection = TRUST_DIRECTION_BIDIRECTIONAL;
else
trustedInfo.TrustDirection = TRUST_DIRECTION_OUTBOUND;
trustedInfo.TrustAttributes = TRUST_ATTRIBUTE_NON_TRANSITIVE;
trustAuth.IncomingAuthInfos = bBidirectional ? 1 : 0;
trustAuth.OutgoingAuthInfos = 1;
trustAuth.IncomingAuthenticationInformation = bBidirectional ? &curr : NULL;
trustAuth.IncomingPreviousAuthenticationInformation = NULL;
trustAuth.OutgoingAuthenticationInformation = &curr;
trustAuth.OutgoingPreviousAuthenticationInformation = NULL;
LSA_HANDLE hTemp = NULL;
status = LsaCreateTrustedDomainEx( hTrusting, &trustedInfo, &trustAuth, 0, &hTemp );
rc = LsaNtStatusToWinError(status);
// if the trust already exists, update its password
if ( status == STATUS_OBJECT_NAME_COLLISION )
{
TRUSTED_DOMAIN_INFORMATION_EX * pTrustedInfo = NULL;
status = LsaQueryTrustedDomainInfo(hTrusting,trustedSid,TrustedDomainInformationEx,(LPVOID*)&pTrustedInfo);
if ( ! status )
{
pTrustedInfo->TrustDirection |= trustedInfo.TrustDirection;
status = LsaSetTrustedDomainInfoByName(hTrusting,&trustedInfo.Name,TrustedDomainInformationEx,(LPVOID*)pTrustedInfo);
if ( ! status )
{
status = LsaSetTrustedDomainInfoByName(hTrusting,&trustedInfo.Name,TrustedDomainAuthInformation,(LPVOID*)&trustAuth);
}
}
rc = LsaNtStatusToWinError(status);
}
if( ! rc )
{
if (hTemp)
LsaClose(hTemp);
}
}
}
return rc;
}
HRESULT
CTrust::CheckAndCreateTrustedSide(
LSA_HANDLE hTrusted,
WCHAR * trustingDomain,
WCHAR * trustedDomain,
WCHAR * trustingComp,
WCHAR * trustedComp,
WCHAR * trustingDNSName,
BYTE * trustingSid,
BOOL bCreate,
BOOL bBidirectional,
BOOL bDownLevel,
BOOL * pbErrorFromTrusting,
BOOL * pbErrorFromTrusted
)
{
DWORD rc = S_OK;
LSA_HANDLE hTrusting = NULL;
NTSTATUS status;
LSA_AUTH_INFORMATION curr;
LSA_AUTH_INFORMATION prev;
WCHAR password[] = L"password";
// set up the auth information for the trust relationship
curr.AuthInfo = (LPBYTE)password;
curr.AuthInfoLength = UStrLen(password) * sizeof(WCHAR);
curr.AuthType = TRUST_AUTH_TYPE_CLEAR;
curr.LastUpdateTime.QuadPart = 0;
prev.AuthInfo = (LPBYTE)password;
prev.AuthInfoLength = UStrLen(password) * sizeof(WCHAR);
prev.AuthType = TRUST_AUTH_TYPE_CLEAR;
prev.LastUpdateTime.QuadPart = 0;
// set up the trusted side of the relationship
if ( IsDownLevel(trustedComp) )
{
// create an inter-domain trust account for the trusting domain on the trusted domain
USER_INFO_1 uInfo;
DWORD parmErr;
WCHAR name[LEN_Account];
memset(&uInfo,0,(sizeof uInfo));
UStrCpy(name,trustingDomain);
name[UStrLen(name) + 1] = 0;
name[UStrLen(name)] = L'$';
if ( ! bCreate )
{
USER_INFO_1 * tempInfo = NULL;
rc = NetUserGetInfo(trustedComp,name,1,(LPBYTE*)&tempInfo);
if ( ! rc )
{
// the trust exists
NetApiBufferFree(tempInfo);
rc = NERR_UserExists;
}
else
{
if ( rc != NERR_UserNotFound )
{
err.SysMsgWrite(ErrE,rc,DCT_MSG_TRUSTING_DOM_GETINFO_FAILED_SSD,trustingDomain,trustedComp,rc);
}
}
}
else
{
// this creates the trust account if it doesn't already exist
// if the account does exist, reset its password
uInfo.usri1_flags = UF_SCRIPT | UF_INTERDOMAIN_TRUST_ACCOUNT;
uInfo.usri1_name = name;
uInfo.usri1_password = password;
uInfo.usri1_priv = 1;
rc = NetUserAdd(trustedComp,1,(LPBYTE)&uInfo,&parmErr);
if ( rc && rc != NERR_UserExists )
{
err.SysMsgWrite(ErrE,rc,DCT_MSG_TRUSTING_DOM_CREATE_FAILED_SSD,trustingDomain,trustedDomain,rc);
}
else if ( rc == NERR_UserExists )
{
// reset the password for the existing trust account
USER_INFO_1003 pwdInfo;
DWORD parmErr;
pwdInfo.usri1003_password = password;
rc = NetUserSetInfo(trustedComp,name,1003,(LPBYTE)&pwdInfo,&parmErr);
}
}
}
else
{
// Win2K, all trusts exist as trusted domain objects
// Create the trustedDomain object.
LSA_UNICODE_STRING sTemp;
TRUSTED_DOMAIN_INFORMATION_EX trustedInfo;
TRUSTED_DOMAIN_AUTH_INFORMATION trustAuth;
InitLsaString(&sTemp, const_cast<WCHAR*>(trustingDomain));
trustedInfo.FlatName = sTemp;
if (bDownLevel)
InitLsaString(&sTemp, trustingDomain);
else
InitLsaString(&sTemp, trustingDNSName);
trustedInfo.Name = sTemp;
trustedInfo.Sid = trustingSid;
if (bDownLevel)
{
trustedInfo.TrustType = TRUST_TYPE_DOWNLEVEL;
}
else
{
trustedInfo.TrustType = TRUST_TYPE_UPLEVEL;
}
if ( bBidirectional )
trustedInfo.TrustDirection = TRUST_DIRECTION_BIDIRECTIONAL;
else
trustedInfo.TrustDirection = TRUST_DIRECTION_INBOUND;
trustedInfo.TrustAttributes = TRUST_ATTRIBUTE_NON_TRANSITIVE;
trustAuth.IncomingAuthInfos = 1;
trustAuth.OutgoingAuthInfos = bBidirectional ? 1 : 0;
trustAuth.OutgoingAuthenticationInformation = bBidirectional ? &curr : NULL;
trustAuth.OutgoingPreviousAuthenticationInformation = NULL;
trustAuth.IncomingAuthenticationInformation = &curr;
trustAuth.IncomingPreviousAuthenticationInformation = NULL;
if ( bCreate )
{
status = LsaCreateTrustedDomainEx( hTrusted, &trustedInfo, &trustAuth, POLICY_VIEW_LOCAL_INFORMATION |
POLICY_TRUST_ADMIN | POLICY_CREATE_SECRET, &hTrusting );
if ( status == STATUS_OBJECT_NAME_COLLISION )
{
TRUSTED_DOMAIN_INFORMATION_EX * pTrustedInfo = NULL;
// Get the old information
status = LsaQueryTrustedDomainInfoByName(hTrusted,&sTemp,TrustedDomainInformationEx,(LPVOID*)&pTrustedInfo);
if ( ! status )
{
pTrustedInfo->TrustAttributes |= trustedInfo.TrustAttributes;
pTrustedInfo->TrustDirection |= trustedInfo.TrustDirection;
status = LsaSetTrustedDomainInfoByName(hTrusted,&sTemp,TrustedDomainInformationEx,pTrustedInfo);
if (! status )
{
status = LsaSetTrustedDomainInfoByName(hTrusted,&sTemp,TrustedDomainAuthInformation,&trustAuth);
}
LsaFreeMemory(pTrustedInfo);
}
}
}
else
{
TRUSTED_DOMAIN_INFORMATION_EX * pTrustedInfo = NULL;
status = LsaQueryTrustedDomainInfoByName(hTrusted,&sTemp,TrustedDomainInformationEx,(LPVOID*)&pTrustedInfo);
if ( ! status )
{
LsaFreeMemory(pTrustedInfo);
}
}
rc = LsaNtStatusToWinError(status);
if ( ! rc )
{
LsaClose(hTrusting);
hTrusting = NULL;
}
}
if ( bCreate && bBidirectional && IsDownLevel(trustingComp) )
{
// set up the trust account for the other side of the relationship
// For Win2K, both sides of the bidirectional trust are handled together,
// but NT4 bidirectional trusts require 2 separate actions
USER_INFO_1 uInfo;
DWORD parmErr;
WCHAR name2[LEN_Account];
memset(&uInfo,0,(sizeof uInfo));
UStrCpy(name2,trustedDomain);
name2[UStrLen(name2) + 1] = 0;
name2[UStrLen(name2)] = L'$';
uInfo.usri1_flags = UF_SCRIPT | UF_INTERDOMAIN_TRUST_ACCOUNT;
uInfo.usri1_name = name2;
uInfo.usri1_password = password;
uInfo.usri1_priv = 1;
rc = NetUserAdd(trustingComp,1,(LPBYTE)&uInfo,&parmErr);
if ( rc == NERR_UserExists )
{
LPUSER_INFO_1 puInfo;
rc = NetUserGetInfo(trustingComp, name2, 1, (LPBYTE*)&puInfo);
if ( !rc )
{
puInfo->usri1_flags &= UF_INTERDOMAIN_TRUST_ACCOUNT;
puInfo->usri1_password = password;
rc = NetUserSetInfo(trustingComp,name2,1,(LPBYTE)puInfo,&parmErr);
NetApiBufferFree(puInfo);
}
else
{
err.MsgWrite(0, DCT_MSG_INVALID_ACCOUNT_S, name2);
}
}
else if ( rc )
{
err.SysMsgWrite(ErrE,rc,DCT_MSG_TRUSTING_DOM_CREATE_FAILED_SSD,trustingDomain,trustedDomain,rc);
}
}
return rc;
}
// Main function used to create trusts
HRESULT
CTrust::CheckAndCreate(
WCHAR * trustingDomain,
WCHAR * trustedDomain,
WCHAR * credDomainTrusting,
WCHAR * credAccountTrusting,
WCHAR * credPasswordTrusting,
WCHAR * credDomainTrusted,
WCHAR * credAccountTrusted,
WCHAR * credPasswordTrusted,
BOOL bCreate,
BOOL bBidirectional,
BOOL * pbErrorFromTrusting,
BOOL * pbErrorFromTrusted
)
{
DWORD rc = 0;
_bstr_t trustingDom;
_bstr_t trustedDom;
_bstr_t trustingComp;
_bstr_t trustedComp;
_bstr_t trustingDNSName;
_bstr_t trustedDNSName;
BYTE trustingSid[200];
BYTE trustedSid[200];
WCHAR name[LEN_Account];
DWORD lenName = DIM(name);
DWORD lenSid = DIM(trustingSid);
SID_NAME_USE snu;
WCHAR * curr = NULL;
BOOL bConnectTrusted = FALSE;
BOOL bConnectTrusting = FALSE;
LSA_HANDLE hTrusting = NULL;
LSA_HANDLE hTrusted = NULL;
BOOL bDownLevel = FALSE;
// Get the DC names, and domain SIDs for the source and target domains
rc = GetDomainNames5(trustingDomain, trustingDom, trustingDNSName);
if (rc)
*pbErrorFromTrusting = TRUE;
if (!rc)
{
rc = GetDomainNames5(trustedDomain, trustedDom, trustedDNSName);
if (rc)
*pbErrorFromTrusted = TRUE;
}
if (!rc)
{
// check whether the trust should be down level or not
if (!trustingDNSName || !trustedDNSName)
bDownLevel = TRUE;
rc = GetDcName5(trustingDom, DS_PDC_REQUIRED, trustingComp);
if ( rc )
{
*pbErrorFromTrusting = TRUE;
err.SysMsgWrite(ErrE,rc,DCT_MSG_GET_DCNAME_FAILED_SD,trustingDom,rc);
}
}
if ( ! rc )
{
rc = GetDcName5(trustedDom, DS_PDC_REQUIRED, trustedComp);
if ( rc )
{
*pbErrorFromTrusted = TRUE;
err.SysMsgWrite(ErrE,rc,DCT_MSG_GET_DCNAME_FAILED_SD,trustedDom,rc);
}
}
if (!rc)
{
if ( credAccountTrusted && *credAccountTrusted )
{
if ( EstablishSession(trustedComp,credDomainTrusted,credAccountTrusted,credPasswordTrusted,TRUE) )
{
bConnectTrusted = TRUE;
}
else
{
rc = GetLastError();
*pbErrorFromTrusted = TRUE;
}
}
}
if (!rc)
{
if ( credAccountTrusting && *credAccountTrusting )
{
if ( EstablishSession(trustingComp,credDomainTrusting,credAccountTrusting,credPasswordTrusting,TRUE) )
{
bConnectTrusting = TRUE;
}
else
{
rc = GetLastError();
*pbErrorFromTrusting = TRUE;
}
}
}
// Need to get the computer name and the SIDs for the domains.
if ( ! rc && ! LookupAccountName(trustingComp,trustingDom,trustingSid,&lenSid,name,&lenName,&snu) )
{
rc = GetLastError();
*pbErrorFromTrusting = TRUE;
err.SysMsgWrite(ErrE,rc,DCT_MSG_GET_DOMAIN_SID_FAILED_1,trustingDom,rc);
}
lenSid = DIM(trustedSid);
lenName = DIM(name);
if (! rc && ! LookupAccountName(trustedComp,trustedDom,trustedSid,&lenSid,name,&lenName,&snu) )
{
rc = GetLastError();
*pbErrorFromTrusted = TRUE;
err.SysMsgWrite(ErrE,rc,DCT_MSG_GET_DOMAIN_SID_FAILED_1,trustedDom,rc);
}
// check whether we are able to call CheckAndCreateTrustedSide and CheckAndCreateTrustingSide
// we need to be able to open policy to trusting and trusted computers with the following access right
// POLICY_VIEW_LOCAL_INFORMATION
// POLICY_TRUST_ADMIN
// POLICY_CREATE_SECRET
if (!rc)
{
NTSTATUS status;
WCHAR* szComputerFailed = NULL;
status = OpenPolicy(trustingComp,
POLICY_VIEW_LOCAL_INFORMATION|POLICY_TRUST_ADMIN|POLICY_CREATE_SECRET,
&hTrusting);
if (status == STATUS_SUCCESS)
{
status = OpenPolicy(trustedComp,
POLICY_VIEW_LOCAL_INFORMATION|POLICY_TRUST_ADMIN|POLICY_CREATE_SECRET,
&hTrusted);
if (status != STATUS_SUCCESS)
{
szComputerFailed = trustedComp;
*pbErrorFromTrusted = TRUE;
}
}
else
{
szComputerFailed = trustingComp;
*pbErrorFromTrusting = TRUE;
}
rc = LsaNtStatusToWinError(status);
if (rc != ERROR_SUCCESS)
err.SysMsgWrite(ErrE, rc, DCT_MSG_LSA_OPEN_FAILED_SD, szComputerFailed, rc);
}
// check the trusted side of the trust first
if ( ! rc )
{
rc = CheckAndCreateTrustedSide(hTrusted, trustingDom,trustedDom,trustingComp,trustedComp,trustingDNSName,trustingSid,
bCreate,bBidirectional, bDownLevel, pbErrorFromTrusting, pbErrorFromTrusted);
}
if ( ! rc )
{
rc = CheckAndCreateTrustingSide(hTrusting,trustingDom,trustedDom,trustingComp,trustedComp,trustedDNSName,trustedSid,
bCreate,bBidirectional, bDownLevel, pbErrorFromTrusting, pbErrorFromTrusted);
}
// close LSA_HANDLE hTrusting and hTrusted
if (hTrusting != NULL)
LsaClose(hTrusting);
if (hTrusted)
LsaClose(hTrusted);
if ( bConnectTrusted )
{
EstablishSession(trustedComp,credDomainTrusted,credAccountTrusted,credPasswordTrusted,FALSE);
}
if ( bConnectTrusting )
{
EstablishSession(trustingComp,credDomainTrusting,credAccountTrusting,credPasswordTrusting,FALSE);
}
return HRESULT_FROM_WIN32(rc);
}
long CTrust::EnumerateTrustedDomains(WCHAR * domain,BOOL bIsTarget,IVarSet * pVarSet,long ndxStart)
{
DWORD rcOs; // OS return code
LSA_HANDLE hPolicy;
NTSTATUS status;
_bstr_t computer;
DOMAIN_CONTROLLER_INFO * pInfo;
WCHAR sName[LEN_Domain];
WCHAR key[100];
long ndxTrust = ndxStart;
/* PDS_DOMAIN_TRUSTS *ChildDomains;
ULONG numChilds;
*/
err.MsgWrite(0,DCT_MSG_ENUMERATING_TRUSTED_DOMAINS_S,domain);
// open a handle to the source domain
rcOs = GetAnyDcName5(domain, computer);
if ( rcOs )
{
err.SysMsgWrite(ErrE,rcOs,DCT_MSG_GET_DCNAME_FAILED_SD,domain,rcOs);
}
if ( ! rcOs )
{
if ( IsDownLevel(computer) )
{
//Enumerate the trusted domains until there are no more to return.
status = OpenPolicy(computer, POLICY_VIEW_LOCAL_INFORMATION ,&hPolicy);
if ( status == STATUS_SUCCESS )
{
LSA_ENUMERATION_HANDLE lsaEnumHandle=0; // start an enum
PLSA_TRUST_INFORMATION trustInfo = NULL;
ULONG ulReturned; // number of items returned
NTSTATUS status;
DWORD rc;
do {
status = LsaEnumerateTrustedDomains(
hPolicy, // open policy handle
&lsaEnumHandle, // enumeration tracker
(void**)&trustInfo, // buffer to receive data
32000, // recommended buffer size
&ulReturned // number of items returned
);
//Check the return status for error.
rc = LsaNtStatusToWinError(status);
if( (rc != ERROR_SUCCESS) &&
(rc != ERROR_MORE_DATA) &&
(rc != ERROR_NO_MORE_ITEMS)
)
{
err.SysMsgWrite(ErrE,rcOs,DCT_MSG_TRUSTED_ENUM_FAILED_SD,domain,rcOs);
}
else
{
// . . . Code to use the Trusted Domain information
for ( ULONG ndx = 0 ; ndx < ulReturned ; ndx++ )
{
_bstr_t direction;
UStrCpy(sName,trustInfo[ndx].Name.Buffer, ( trustInfo[ndx].Name.Length / (sizeof WCHAR)) + 1);
TRUSTED_DOMAIN_INFORMATION_EX * pTrustedInfo = NULL;
status = LsaQueryTrustedDomainInfo(hPolicy,trustInfo[ndx].Sid,TrustedDomainInformationEx,(LPVOID*)&pTrustedInfo);
if ( ! status )
{
switch ( pTrustedInfo->TrustDirection )
{
case TRUST_DIRECTION_DISABLED:
direction = GET_BSTR(IDS_TRUST_DIRECTION_DISABLED);
break;
case TRUST_DIRECTION_INBOUND:
direction = GET_BSTR(IDS_TRUST_DIRECTION_INBOUND);
break;
case TRUST_DIRECTION_OUTBOUND:
direction = GET_BSTR(IDS_TRUST_DIRECTION_OUTBOUND);
break;
case TRUST_DIRECTION_BIDIRECTIONAL:
direction = GET_BSTR(IDS_TRUST_DIRECTION_BIDIRECTIONAL);
break;
default:
break;
};
if ( ! bIsTarget )
{
swprintf(key,L"Trusts.%ld.Type",ndxTrust);
pVarSet->put(key, GET_BSTR(IDS_TRUST_RELATION_EXTERNAL));
}
LsaFreeMemory(pTrustedInfo);
}
else
{
rcOs = LsaNtStatusToWinError(status);
// My logic here is that we are checking Trusted domains here so this is atleast true
// check whether this trust is already listed as an inbound trust
//* direction = L"Outbound";
direction = GET_BSTR(IDS_TRUST_DIRECTION_OUTBOUND);
}
if ( ! bIsTarget )
{
swprintf(key,L"Trusts.%ld",ndxTrust);
pVarSet->put(key,sName);
swprintf(key,L"Trusts.%ld.Direction",ndxTrust);
pVarSet->put(key,direction);
swprintf(key,L"Trusts.%ld.ExistsForTarget",ndxTrust);
//* pVarSet->put(key,L"No");
pVarSet->put(key,GET_BSTR(IDS_No));
err.MsgWrite(0,DCT_MSG_SOURCE_TRUSTS_THIS_SS,sName,domain);
}
long ndx2 = FindInboundTrust(pVarSet,sName,ndxTrust);
if ( ndx2 != -1 )
{
if ( ! bIsTarget )
{
// we've already seen this trust as an inbound trust
// update the existing record!
WCHAR key2[1000];
swprintf(key2,L"Trusts.%ld.Direction",ndx2);
//* pVarSet->put(key2,L"Bidirectional");
pVarSet->put(key2,GET_BSTR(IDS_TRUST_DIRECTION_BIDIRECTIONAL));
continue; // don't update the trust entry index, since we used the existing
// entry instead of creating a new one
}
else
{
swprintf(key,L"Trusts.%ld.ExistsForTarget",ndx2);
//* pVarSet->put(key,L"Yes");
pVarSet->put(key,GET_BSTR(IDS_YES));
err.MsgWrite(0,DCT_MSG_TARGET_TRUSTS_THIS_SS,domain,sName);
}
}
swprintf(key,L"Trusts.%ld.ExistsForTarget",ndxTrust);
// check the trusted domain, to see if the target already trusts it
//if ( UStrICmp(sName,target) )
// {
// continue;
// }
if ( ! bIsTarget )
ndxTrust++;
}
// Free the buffer.
LsaFreeMemory(trustInfo);
}
} while (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA );
LsaClose(hPolicy);
}
}
else
{
ULONG ulCount;
PDS_DOMAIN_TRUSTS pDomainTrusts;
DWORD dwError = DsEnumerateDomainTrusts(
computer,
DS_DOMAIN_IN_FOREST|DS_DOMAIN_DIRECT_INBOUND|DS_DOMAIN_DIRECT_OUTBOUND,
&pDomainTrusts,
&ulCount
);
if (dwError == NO_ERROR)
{
ULONG ulIndex;
ULONG ulDomainIndex = (ULONG)-1L;
ULONG ulParentIndex = (ULONG)-1L;
// find local domain
for (ulIndex = 0; ulIndex < ulCount; ulIndex++)
{
if (pDomainTrusts[ulIndex].Flags & DS_DOMAIN_PRIMARY)
{
ulDomainIndex = ulIndex;
if (!(pDomainTrusts[ulIndex].Flags & DS_DOMAIN_TREE_ROOT))
{
ulParentIndex = pDomainTrusts[ulIndex].ParentIndex;
}
break;
}
}
for (ulIndex = 0; ulIndex < ulCount; ulIndex++)
{
DS_DOMAIN_TRUSTS& rDomainTrust = pDomainTrusts[ulIndex];
// filter out indirect trusts
if (!(rDomainTrust.Flags & (DS_DOMAIN_DIRECT_INBOUND|DS_DOMAIN_DIRECT_OUTBOUND)))
{
continue;
}
// trusted or trusting domain name
_bstr_t bstrName(rDomainTrust.DnsDomainName ? rDomainTrust.DnsDomainName : rDomainTrust.NetbiosDomainName);
// trust direction
_bstr_t bstrDirection;
switch (rDomainTrust.Flags & (DS_DOMAIN_DIRECT_INBOUND|DS_DOMAIN_DIRECT_OUTBOUND))
{
case DS_DOMAIN_DIRECT_INBOUND:
bstrDirection = GET_BSTR(IDS_TRUST_DIRECTION_INBOUND);
break;
case DS_DOMAIN_DIRECT_OUTBOUND:
bstrDirection = GET_BSTR(IDS_TRUST_DIRECTION_OUTBOUND);
break;
case DS_DOMAIN_DIRECT_INBOUND|DS_DOMAIN_DIRECT_OUTBOUND:
bstrDirection = GET_BSTR(IDS_TRUST_DIRECTION_BIDIRECTIONAL);
break;
default:
// bstrDirection = ;
break;
}
// trust relationship
_bstr_t bstrRelationship;
if (ulIndex == ulParentIndex)
{
bstrRelationship = GET_BSTR(IDS_TRUST_RELATION_PARENT);
}
else if (rDomainTrust.Flags & DS_DOMAIN_IN_FOREST)
{
if (rDomainTrust.ParentIndex == ulDomainIndex)
{
bstrRelationship = GET_BSTR(IDS_TRUST_RELATION_CHILD);
}
else if ((rDomainTrust.Flags & DS_DOMAIN_TREE_ROOT) && (pDomainTrusts[ulDomainIndex].Flags & DS_DOMAIN_TREE_ROOT))
{
bstrRelationship = GET_BSTR(IDS_TRUST_RELATION_ROOT);
}
else
{
bstrRelationship = GET_BSTR(IDS_TRUST_RELATION_SHORTCUT);
}
}
else
{
switch (rDomainTrust.TrustType)
{
case TRUST_TYPE_DOWNLEVEL:
case TRUST_TYPE_UPLEVEL:
bstrRelationship = (rDomainTrust.TrustAttributes & TRUST_ATTRIBUTE_FOREST_TRANSITIVE) ? GET_BSTR(IDS_TRUST_RELATION_FOREST) : GET_BSTR(IDS_TRUST_RELATION_EXTERNAL);
break;
case TRUST_TYPE_MIT:
bstrRelationship = GET_BSTR(IDS_TRUST_RELATION_MIT);
break;
default:
bstrRelationship = GET_BSTR(IDS_TRUST_RELATION_UNKNOWN);
break;
}
}
if (bIsTarget)
{
// if same trust was found on source domain and the trust
// directions match update exists for target to yes
LONG lSourceIndex = FindInboundTrust(pVarSet, bstrName, ndxTrust);
if (lSourceIndex >= 0)
{
// get source trust direction
swprintf(key, L"Trusts.%ld.Direction", lSourceIndex);
_bstr_t bstrSourceDirection = pVarSet->get(key);
// if target trust direction is bi-directional or
// target trust direction equals source trust direction
// then set exists for target to yes
bool bExists = false;
if (bstrDirection == GET_BSTR(IDS_TRUST_DIRECTION_BIDIRECTIONAL))
{
bExists = true;
}
else if (bstrDirection == bstrSourceDirection)
{
bExists = true;
}
if (bExists)
{
swprintf(key, L"Trusts.%ld.ExistsForTarget", lSourceIndex);
pVarSet->put(key, GET_BSTR(IDS_YES));
// write trust directions to log
if (rDomainTrust.Flags & DS_DOMAIN_DIRECT_OUTBOUND)
{
err.MsgWrite(0, DCT_MSG_TARGET_TRUSTS_THIS_SS, domain, (LPCTSTR)bstrName);
}
if (rDomainTrust.Flags & DS_DOMAIN_DIRECT_INBOUND)
{
err.MsgWrite(0, DCT_MSG_TARGET_TRUSTED_BY_THIS_SS, domain, (LPCTSTR)bstrName);
}
}
}
}
else
{
// domain name
swprintf(key, L"Trusts.%ld", ndxTrust);
pVarSet->put(key, bstrName);
// trust direction
swprintf(key, L"Trusts.%ld.Direction", ndxTrust);
pVarSet->put(key, bstrDirection);
// trust relationship
if (bstrRelationship.length() > 0)
{
swprintf(key, L"Trusts.%ld.Type", ndxTrust);
pVarSet->put(key, bstrRelationship);
}
// trust exists on target
// initially set to no until target domain is enumerated
swprintf(key, L"Trusts.%ld.ExistsForTarget", ndxTrust);
pVarSet->put(key, GET_BSTR(IDS_No));
// write trust directions to log
if (rDomainTrust.Flags & DS_DOMAIN_DIRECT_OUTBOUND)
{
err.MsgWrite(0, DCT_MSG_SOURCE_TRUSTS_THIS_SS, (LPCTSTR)bstrName, domain);
}
if (rDomainTrust.Flags & DS_DOMAIN_DIRECT_INBOUND)
{
err.MsgWrite(0, DCT_MSG_SOURCE_IS_TRUSTED_BY_THIS_SS, (LPCTSTR)bstrName, domain);
}
++ndxTrust;
}
}
NetApiBufferFree(pDomainTrusts);
}
else
{
err.SysMsgWrite(ErrE, dwError, DCT_MSG_TRUSTED_ENUM_FAILED_SD, domain, dwError);
}
}
}
if ( bIsTarget )
{
// make sure we have "Yes" for the target domain itself
long ndx2 = FindInboundTrust(pVarSet,domain,ndxTrust);
if ( ndx2 != -1 )
{
swprintf(key,L"Trusts.%ld.ExistsForTarget",ndx2);
//* pVarSet->put(key,L"Yes");
pVarSet->put(key,GET_BSTR(IDS_YES));
}
}
return ndxTrust;
}
long CTrust::EnumerateTrustingDomains(WCHAR * domain,BOOL bIsTarget,IVarSet * pVarSet,long ndxStart)
{
DWORD rcOs; // OS return code
DWORD hEnum=0; // enumeration handle
USER_INFO_1 * pNetUsers=NULL; // NetUserEnum array buffer
USER_INFO_1 * pNetUser; // NetUserEnum array item
DWORD nRead; // Entries read.
DWORD nTotal; // Entries total.
WCHAR sName[LEN_Domain]; // Domain name
WCHAR * pNameEnd; // Null at end
_bstr_t computer;
DOMAIN_CONTROLLER_INFO * pInfo;
long ndx = ndxStart;
WCHAR key[100];
err.MsgWrite(0,DCT_MSG_ENUMERATING_TRUSTING_DOMAINS_S,domain);
rcOs = GetAnyDcName5(domain, computer);
if ( rcOs )
{
return ndx;
}
// get the trusting domains for the NT 4 domain
// for Win2K domains, the trusting domains will be listed as Incoming in the Trusted Domain enumeration
if ( IsDownLevel(computer) )
{
do
{
nRead = 0;
nTotal = 0;
rcOs = NetUserEnum(
computer,
1,
FILTER_INTERDOMAIN_TRUST_ACCOUNT,
(BYTE **) &pNetUsers,
10240,
&nRead,
&nTotal,
&hEnum );
switch ( rcOs )
{
case 0:
case ERROR_MORE_DATA:
for ( pNetUser = pNetUsers;
pNetUser < pNetUsers + nRead;
pNetUser++ )
{
// skip trust accounts whose password age is older than 30 days to avoid
// delays caused by trying to enumerate defunct trusts
if ( pNetUser->usri1_password_age > 60 * 60 * 24 * 30 ) // 30 days (age is in seconds)
{
err.MsgWrite(0,DCT_MSG_SKIPPING_OLD_TRUST_SD,pNetUser->usri1_name,
pNetUser->usri1_password_age / ( 60*60*24) );
continue;
}
safecopy( sName, pNetUser->usri1_name );
pNameEnd = sName + UStrLen( sName );
if ( (pNameEnd > sName) && (pNameEnd[-1] == L'$') )
{
pNameEnd[-1] = L'\0';
}
if ( *sName )
{
// Found a (probably) valid trust!
if ( ! bIsTarget )
{
// for the source domain, simply add the trusts to the list in the varset
swprintf(key,L"Trusts.%ld",ndx);
pVarSet->put(key,sName);
swprintf(key,L"Trusts.%ld.Direction",ndx);
//* pVarSet->put(key,L"Inbound");
pVarSet->put(key,GET_BSTR(IDS_TRUST_DIRECTION_INBOUND));
swprintf(key,L"Trusts.%ld.Type",ndx);
pVarSet->put(key, GET_BSTR(IDS_TRUST_RELATION_EXTERNAL));
swprintf(key,L"Trusts.%ld.ExistsForTarget",ndx);
//* pVarSet->put(key,L"No");
pVarSet->put(key,GET_BSTR(IDS_No));
err.MsgWrite(0,DCT_MSG_SOURCE_IS_TRUSTED_BY_THIS_SS,sName,domain);
ndx++;
}
else
{
// for the target domain, look for this trust in the varset
// and if it is there, mark that it exists on the target
long ndxTemp = FindInboundTrust(pVarSet,sName,ndxStart);
if ( ndxTemp != -1 )
{
swprintf(key,L"Trusts.%ld.ExistsForTarget",ndxTemp);
//* pVarSet->put(key,L"Yes");
pVarSet->put(key,GET_BSTR(IDS_YES));
err.MsgWrite(0,DCT_MSG_TARGET_TRUSTS_THIS_SS,sName,domain);
}
}
}
}
break;
default:
break;
}
if ( pNetUsers )
{
NetApiBufferFree( pNetUsers );
pNetUsers = NULL;
}
} while ( rcOs == ERROR_MORE_DATA );
}
// Win2K domain, don't need to enumerate the trusting domains here - they will all be included in the
// trusted domain enum
return ndx;
}
/*void CheckProc(void * arg,void * data)
{
CTrust * tr = (CTrust*)arg;
}*/
STDMETHODIMP CTrust::PreMigrationTask(/* [in] */IUnknown * pVarSet)
{
/* IVarSetPtr pVS = pVarSet;
BOOL bCreate;
_bstr_t source = pVS->get(GET_BSTR(DCTVS_Options_SourceDomain));
_bstr_t target = pVS->get(GET_BSTR(DCTVS_Options_TargetDomain));
_bstr_t logfile = pVS->get(GET_BSTR(DCTVS_Options_Logfile));
_bstr_t localOnly = pVS->get(GET_BSTR(DCTVS_Options_LocalProcessingOnly));
_bstr_t docreate = pVS->get(L"Options.CreateTrusts");
if ( !UStrICmp(localOnly,GET_STRING(IDS_YES)) )
{
// don't do anything in local agent mode
return S_OK;
}
if ( !UStrICmp(docreate,GET_STRING(IDS_YES)) )
{
bCreate = TRUE;
}
else
{
bCreate = FALSE;
}
pVS->put(GET_BSTR(DCTVS_CurrentOperation),L"Verifying trust relationships");
err.LogOpen(logfile,1);
err.LevelBeepSet(1000);
err.LogClose();
*/
return S_OK;
}
STDMETHODIMP CTrust::PostMigrationTask(/* [in] */IUnknown * pVarSet)
{
return S_OK;
}
STDMETHODIMP CTrust::GetName(/* [out] */BSTR * name)
{
(*name) = SysAllocString(L"Trust Manager");
return S_OK;
}
STDMETHODIMP CTrust::GetResultString(/* [in] */IUnknown * pVarSet,/* [out] */ BSTR * text)
{
WCHAR buffer[100] = L"";
IVarSetPtr pVS;
pVS = pVarSet;
(*text) = SysAllocString(buffer);
return S_OK;
}
STDMETHODIMP CTrust::StoreResults(/* [in] */IUnknown * pVarSet)
{
return S_OK;
}
STDMETHODIMP CTrust::ConfigureSettings(/*[in]*/IUnknown * pVarSet)
{
return S_OK;
}
STDMETHODIMP CTrust::QueryTrusts(BSTR domainSource,BSTR domainTarget, BSTR sLogFile, IUnknown **pVarSet)
{
HRESULT hr = S_OK;
IVarSetPtr pVS(CLSID_VarSet);
long ndx;
_bstr_t sFile = sLogFile;
err.LogOpen((WCHAR*) sFile, 1);
err.LevelBeepSet(1000);
hr = pVS.QueryInterface(IID_IUnknown,(long**)pVarSet);
// Add a blank line to help differentiate different runs
err.MsgWrite(0,DCT_MSG_GENERIC_S,L"");
ndx = EnumerateTrustingDomains(domainSource,FALSE,pVS,0);
EnumerateTrustingDomains(domainTarget,TRUE,pVS,0);
ndx = EnumerateTrustedDomains(domainSource,FALSE,pVS,ndx);
EnumerateTrustedDomains(domainTarget,TRUE,pVS,ndx);
//err.LogClose();
pVS->put(L"Trusts",ndx);
return hr;
}