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.
554 lines
18 KiB
554 lines
18 KiB
//++
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1987 - 1999
|
|
//
|
|
// Module Name:
|
|
//
|
|
// trust.c
|
|
//
|
|
// Abstract:
|
|
//
|
|
// Queries into network drivers
|
|
//
|
|
// Author:
|
|
//
|
|
// Anilth - 4-20-1998
|
|
//
|
|
// Environment:
|
|
//
|
|
// User mode only.
|
|
// Contains NT-specific code.
|
|
//
|
|
// Revision History:
|
|
//
|
|
//--
|
|
|
|
#include "precomp.h"
|
|
|
|
|
|
|
|
|
|
|
|
BOOL DomainSidRight( IN PTESTED_DOMAIN TestedDomain,
|
|
NETDIAG_PARAMS* pParams, NETDIAG_RESULT* pResults
|
|
);
|
|
|
|
|
|
HRESULT TrustTest( NETDIAG_PARAMS* pParams, NETDIAG_RESULT* pResults)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
PTESTED_DOMAIN Context = pParams->pDomain;
|
|
|
|
NET_API_STATUS NetStatus;
|
|
|
|
PNETLOGON_INFO_2 NetlogonInfo2 = NULL;
|
|
|
|
NET_API_STATUS TrustedNetStatus = 0;
|
|
LPWSTR TrustedDomainList = NULL;
|
|
PTESTED_DOMAIN TestedDomain = pResults->Global.pMemberDomain;
|
|
PLIST_ENTRY ListEntry;
|
|
LPBYTE InputDataPtr;
|
|
int i;
|
|
|
|
// validDC is the count of valid Domain Controllers with which secure channel can be set.
|
|
int validDC = 0;
|
|
|
|
|
|
InitializeListHead(&pResults->Trust.lmsgOutput);
|
|
|
|
PrintStatusMessage(pParams, 4, IDS_TRUST_STATUS_MSG);
|
|
|
|
//
|
|
// Only Members and BDCs have trust relationships to their primary domain
|
|
//
|
|
|
|
if (!
|
|
(pResults->Global.pPrimaryDomainInfo->MachineRole == DsRole_RoleMemberWorkstation ||
|
|
pResults->Global.pPrimaryDomainInfo->MachineRole == DsRole_RoleMemberServer ||
|
|
pResults->Global.pPrimaryDomainInfo->MachineRole == DsRole_RoleBackupDomainController )
|
|
)
|
|
{
|
|
PrintStatusMessage(pParams, 0, IDS_GLOBAL_SKIP_NL);
|
|
return hr; // not to test standalone
|
|
}
|
|
|
|
pResults->Trust.fPerformed = TRUE;
|
|
//
|
|
// Check to see that the domain Sid of the primary domain is right.
|
|
//
|
|
|
|
if ( !DomainSidRight( pResults->Global.pMemberDomain, pParams, pResults ) ) {
|
|
hr = S_FALSE;
|
|
goto L_ERR;
|
|
}
|
|
|
|
//
|
|
// Use the secure channel
|
|
//
|
|
// If some other caller did this in the recent past,
|
|
// this doesn't even use the secure channel.
|
|
//
|
|
// On a BDC, this doesn't use the secure channel.
|
|
//
|
|
|
|
TrustedNetStatus = NetEnumerateTrustedDomains( NULL, &TrustedDomainList );
|
|
if ( TrustedNetStatus != NO_ERROR ) {
|
|
AddIMessageToList(&pResults->Trust.lmsgOutput, Nd_Quiet, 0,
|
|
IDS_TRUST_FAILED_LISTDOMAINS,
|
|
pResults->Global.pPrimaryDomainInfo->DomainNameFlat,
|
|
NetStatusToString(TrustedNetStatus));
|
|
}
|
|
|
|
// Don't complain yet since the real secure channel status is more
|
|
// important to the user.
|
|
|
|
//
|
|
// Check the current status of the secure channel.
|
|
// (This may still be cached and out of date.)
|
|
//
|
|
|
|
InputDataPtr = (LPBYTE)(pResults->Global.pPrimaryDomainInfo->DomainNameDns ?
|
|
pResults->Global.pPrimaryDomainInfo->DomainNameDns :
|
|
pResults->Global.pPrimaryDomainInfo->DomainNameFlat);
|
|
|
|
NetStatus = I_NetLogonControl2(
|
|
NULL,
|
|
NETLOGON_CONTROL_TC_QUERY,
|
|
2, // Query level
|
|
(LPBYTE)&(InputDataPtr),
|
|
(LPBYTE *)&NetlogonInfo2 );
|
|
|
|
|
|
// put message to message list
|
|
if ( NetStatus != NO_ERROR )
|
|
{
|
|
//IDS_TRUST_FAILED_SECURECHANNEL " Cannot get secure channel status for domain '%ws' from Netlogon. [%s]"
|
|
AddIMessageToList(&pResults->Trust.lmsgOutput, Nd_Quiet, 0,
|
|
IDS_TRUST_FAILED_SECURECHANNEL,
|
|
pResults->Global.pPrimaryDomainInfo->DomainNameFlat,
|
|
NetStatusToString(NetStatus));
|
|
hr = S_FALSE;
|
|
goto L_ERR;
|
|
}
|
|
|
|
if ( NetlogonInfo2->netlog2_tc_connection_status != NO_ERROR )
|
|
{
|
|
//IDS_TRUST_CHANNEL_BROKEN " [FATAL] Secure channel to domain '%ws' is broken. [%s]\n"
|
|
AddIMessageToList(&pResults->Trust.lmsgOutput, Nd_Quiet, 0,
|
|
IDS_TRUST_CHANNEL_BROKEN,
|
|
pResults->Global.pPrimaryDomainInfo->DomainNameFlat,
|
|
NetStatusToString(NetlogonInfo2->netlog2_tc_connection_status));
|
|
hr = S_FALSE;
|
|
goto L_ERR;
|
|
}
|
|
|
|
AddIMessageToList(&pResults->Trust.lmsgOutput, Nd_Verbose, 0,
|
|
IDS_TRUST_SECURECHANNEL_TO,
|
|
pResults->Global.pPrimaryDomainInfo->DomainNameFlat,
|
|
NetlogonInfo2->netlog2_trusted_dc_name);
|
|
|
|
|
|
// free the data buffer returned earlies
|
|
if ( NetlogonInfo2 != NULL ) {
|
|
NetApiBufferFree( NetlogonInfo2 );
|
|
NetlogonInfo2 = NULL;
|
|
}
|
|
|
|
// test further
|
|
switch(pResults->Global.pPrimaryDomainInfo->MachineRole){
|
|
//
|
|
// On a backup domain controller,
|
|
// only setup a secure channel to the PDC.
|
|
//
|
|
case DsRole_RoleBackupDomainController:
|
|
//
|
|
// Check the current status of the secure channel.
|
|
// (This may be still cached and out of date.)
|
|
//
|
|
|
|
NetlogonInfo2 = NULL;
|
|
InputDataPtr = (LPBYTE)(pResults->Global.pPrimaryDomainInfo->DomainNameDns ?
|
|
pResults->Global.pPrimaryDomainInfo->DomainNameDns :
|
|
pResults->Global.pPrimaryDomainInfo->DomainNameFlat);
|
|
|
|
// connect to PDC
|
|
NetStatus = I_NetLogonControl2(
|
|
NULL,
|
|
NETLOGON_CONTROL_REDISCOVER,
|
|
2, // Query level
|
|
(LPBYTE)&InputDataPtr,
|
|
(LPBYTE *)&NetlogonInfo2 );
|
|
|
|
if (NetStatus == ERROR_ACCESS_DENIED)
|
|
{
|
|
//IDS_TRUST_NOT_ADMIN " Cannot test secure channel to PDC since you are not an administrator.\n"
|
|
AddIMessageToList(&pResults->Trust.lmsgOutput, Nd_Quiet, 0,
|
|
IDS_TRUST_NOT_ADMIN);
|
|
goto L_ERR;
|
|
}
|
|
|
|
|
|
if(NetStatus != NO_ERROR)
|
|
{
|
|
//IDS_TRUST_FAILED_CHANNEL_PDC " [FATAL] Cannot set secure channel for domain '%ws' to PDC. [%s]\n"
|
|
AddIMessageToList(&pResults->Trust.lmsgOutput, Nd_Quiet, 0,
|
|
IDS_TRUST_FAILED_CHANNEL_PDC,
|
|
pResults->Global.pPrimaryDomainInfo->DomainNameFlat,
|
|
NetStatusToString(NetStatus));
|
|
hr = S_FALSE;
|
|
goto L_ERR;
|
|
}
|
|
|
|
if ( NetlogonInfo2->netlog2_tc_connection_status != NO_ERROR )
|
|
{
|
|
AddIMessageToList(&pResults->Trust.lmsgOutput, Nd_Quiet, 0,
|
|
IDS_TRUST_FAILED_CHANNEL_PDC,
|
|
pResults->Global.pPrimaryDomainInfo->DomainNameFlat,
|
|
NetStatusToString(NetStatus));
|
|
hr = S_FALSE;
|
|
goto L_ERR;
|
|
}
|
|
|
|
AddIMessageToList(&pResults->Trust.lmsgOutput, Nd_ReallyVerbose, 0,
|
|
IDS_TRUST_SECURECHANNEL_TOPDC,
|
|
pResults->Global.pPrimaryDomainInfo->DomainNameFlat,
|
|
NetlogonInfo2->netlog2_trusted_dc_name);
|
|
|
|
|
|
if ( NetlogonInfo2 != NULL )
|
|
{
|
|
NetApiBufferFree( NetlogonInfo2 );
|
|
NetlogonInfo2 = NULL;
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
// On a workstation or member server,
|
|
// try the secure channel to ever DC in the domain.
|
|
//
|
|
|
|
case DsRole_RoleMemberServer:
|
|
case DsRole_RoleMemberWorkstation:
|
|
|
|
if ( TestedDomain->NetbiosDomainName == NULL ) {
|
|
//IDS_TRUST_NO_NBT_DOMAIN " [FATAL] Cannot test secure channel since no netbios domain name '%ws' to DC '%ws'."
|
|
AddMessageToList( &pResults->Trust.lmsgOutput, Nd_Quiet, IDS_TRUST_NO_NBT_DOMAIN, TestedDomain->PrintableDomainName );
|
|
PrintGuruMessage2(" [FATAL] Cannot test secure channel since no netbios domain name '%ws' to DC '%ws'.", TestedDomain->PrintableDomainName );
|
|
PrintGuru( 0, NETLOGON_GURU );
|
|
hr = S_FALSE;
|
|
goto L_ERR;
|
|
}
|
|
|
|
//
|
|
// Ensure secure channel can be set with atleast one DC.
|
|
//
|
|
|
|
for ( ListEntry = TestedDomain->TestedDcs.Flink ;
|
|
ListEntry != &TestedDomain->TestedDcs ;
|
|
ListEntry = ListEntry->Flink )
|
|
{
|
|
WCHAR RediscoverName[MAX_PATH+1+MAX_PATH+1];
|
|
PTESTED_DC TestedDc;
|
|
|
|
|
|
//
|
|
// Loop through the list of DCs in this domain
|
|
//
|
|
|
|
TestedDc = CONTAINING_RECORD( ListEntry, TESTED_DC, Next );
|
|
|
|
if ( TestedDc->Flags & DC_IS_DOWN ) {
|
|
AddIMessageToList(&pResults->Trust.lmsgOutput, Nd_ReallyVerbose, 0,
|
|
IDS_TRUST_NOTESTASITSDOWN,
|
|
TestedDc->ComputerName );
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Build the name to rediscover
|
|
//
|
|
|
|
wcscpy( RediscoverName, GetSafeStringW(TestedDomain->DnsDomainName ?
|
|
TestedDomain->DnsDomainName :
|
|
TestedDomain->NetbiosDomainName));
|
|
wcscat( RediscoverName, L"\\" );
|
|
wcscat( RediscoverName, GetSafeStringW(TestedDc->ComputerName) );
|
|
|
|
|
|
//
|
|
// Check the current status of the secure channel.
|
|
// (This may be still cached and out of date.)
|
|
//
|
|
|
|
InputDataPtr = (LPBYTE)RediscoverName;
|
|
NetStatus = I_NetLogonControl2(
|
|
NULL,
|
|
NETLOGON_CONTROL_REDISCOVER,
|
|
2, // Query level
|
|
(LPBYTE)&InputDataPtr,
|
|
(LPBYTE *)&NetlogonInfo2 );
|
|
|
|
if ( NetStatus != NO_ERROR )
|
|
{
|
|
if ( ERROR_ACCESS_DENIED == NetStatus )
|
|
{
|
|
AddIMessageToList(&pResults->Trust.lmsgOutput, Nd_Quiet, 0,
|
|
IDS_TRUST_TODCS_NOT_ADMIN);
|
|
}
|
|
else
|
|
{
|
|
//IDS_TRUST_FAILED_TODCS " Cannot test secure channel for domain '%ws' to DC '%ws'. [%s]\n"
|
|
AddIMessageToList(&pResults->Trust.lmsgOutput, Nd_Quiet, 0,
|
|
IDS_TRUST_FAILED_TODCS,
|
|
TestedDomain->PrintableDomainName,
|
|
TestedDc->NetbiosDcName,
|
|
NetStatusToString(NetStatus));
|
|
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if ( NetlogonInfo2->netlog2_tc_connection_status != NO_ERROR )
|
|
{
|
|
AddIMessageToList(&pResults->Trust.lmsgOutput, Nd_Quiet, 0,
|
|
IDS_TRUST_FAILED_CHANNEL_DCS,
|
|
TestedDomain->PrintableDomainName,
|
|
TestedDc->NetbiosDcName );
|
|
continue;
|
|
}
|
|
|
|
AddIMessageToList(&pResults->Trust.lmsgOutput, Nd_ReallyVerbose, 0,
|
|
IDS_TRUST_CHANNEL_DC,
|
|
TestedDomain->PrintableDomainName,
|
|
NetlogonInfo2->netlog2_trusted_dc_name );
|
|
validDC++;
|
|
}
|
|
if (validDC == 0)
|
|
hr = S_FALSE;
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
|
|
L_ERR:
|
|
|
|
if ( NetlogonInfo2 != NULL ) {
|
|
NetApiBufferFree( NetlogonInfo2 );
|
|
NetlogonInfo2 = NULL;
|
|
}
|
|
|
|
if ( TrustedDomainList != NULL ) {
|
|
NetApiBufferFree( TrustedDomainList );
|
|
TrustedDomainList = NULL;
|
|
}
|
|
|
|
PrintStatusMessage(pParams, 0, FHrOK(hr) ? IDS_GLOBAL_PASS_NL : IDS_GLOBAL_FAIL_NL);
|
|
|
|
pResults->Trust.hr = hr;
|
|
|
|
return hr;
|
|
}
|
|
|
|
void TrustGlobalPrint(IN NETDIAG_PARAMS *pParams, IN OUT NETDIAG_RESULT *pResults)
|
|
{
|
|
// print out the test result
|
|
if (pParams->fVerbose || !FHrOK(pResults->Trust.hr))
|
|
{
|
|
PrintNewLine(pParams, 2);
|
|
PrintTestTitleResult(pParams, IDS_TRUST_LONG, IDS_TRUST_SHORT, pResults->Trust.fPerformed,
|
|
pResults->Trust.hr, 0);
|
|
|
|
PrintMessageList(pParams, &pResults->Trust.lmsgOutput);
|
|
}
|
|
|
|
}
|
|
|
|
void TrustPerInterfacePrint(IN NETDIAG_PARAMS *pParams,
|
|
IN OUT NETDIAG_RESULT *pResults,
|
|
IN INTERFACE_RESULT *pIfResult)
|
|
{
|
|
// no perinterface information
|
|
}
|
|
|
|
void TrustCleanup(IN NETDIAG_PARAMS *pParams,
|
|
IN OUT NETDIAG_RESULT *pResults)
|
|
{
|
|
MessageListCleanUp(&pResults->Trust.lmsgOutput);
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
DomainSidRight(
|
|
IN PTESTED_DOMAIN TestedDomain,
|
|
NETDIAG_PARAMS* pParams, NETDIAG_RESULT* pResults
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine if the DomainSid field of the TestDomain matches the DomainSid
|
|
of the domain.
|
|
|
|
Arguments:
|
|
|
|
TestedDomain - Domain to test
|
|
|
|
Return Value:
|
|
|
|
TRUE: Test suceeded.
|
|
FALSE: Test failed
|
|
|
|
--*/
|
|
{
|
|
NET_API_STATUS NetStatus;
|
|
NTSTATUS Status;
|
|
BOOL RetVal = TRUE;
|
|
|
|
SAM_HANDLE LocalSamHandle = NULL;
|
|
SAM_HANDLE DomainHandle = NULL;
|
|
|
|
PTESTED_DC pTestedDc;
|
|
|
|
|
|
//
|
|
// Initialization
|
|
//
|
|
|
|
AddIMessageToList(&pResults->Trust.lmsgOutput, Nd_ReallyVerbose, 0,
|
|
IDS_TRUST_ENSURESID,
|
|
TestedDomain->PrintableDomainName);
|
|
|
|
if ( TestedDomain->DomainSid == NULL ) {
|
|
AddIMessageToList(&pResults->Trust.lmsgOutput, Nd_Quiet, 0,
|
|
IDS_TRUST_MISSINGSID,
|
|
TestedDomain->PrintableDomainName);
|
|
RetVal = FALSE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// If we don't yet know a DC in the domain,
|
|
// find one.
|
|
//
|
|
|
|
if ( TestedDomain->DcInfo == NULL )
|
|
{
|
|
LPTSTR pszDcType;
|
|
|
|
if ( TestedDomain->fTriedToFindDcInfo ) {
|
|
//IDS_DCLIST_NO_DC " '%ws': Cannot find DC to get DC list from [test skiped].\n"
|
|
AddMessageToList( &pResults->Trust.lmsgOutput, Nd_Verbose, IDS_TRUST_NODC, TestedDomain->PrintableDomainName);
|
|
goto Cleanup;
|
|
}
|
|
|
|
pszDcType = LoadAndAllocString(IDS_DCTYPE_DC);
|
|
NetStatus = DoDsGetDcName( pParams,
|
|
pResults,
|
|
&pResults->Trust.lmsgOutput,
|
|
TestedDomain,
|
|
DS_DIRECTORY_SERVICE_PREFERRED,
|
|
pszDcType, //"DC",
|
|
FALSE,
|
|
&TestedDomain->DcInfo );
|
|
Free(pszDcType);
|
|
|
|
TestedDomain->fTriedToFindDcInfo = TRUE;
|
|
|
|
if ( NetStatus != NO_ERROR ) {
|
|
//IDS_TRUST_NODC " '%ws': Cannot find DC to get DC list from [test skiped].\n"
|
|
AddIMessageToList(&pResults->Trust.lmsgOutput, Nd_Verbose, 0,
|
|
IDS_TRUST_NODC, TestedDomain->PrintableDomainName);
|
|
AddIMessageToList(&pResults->Trust.lmsgOutput, Nd_Verbose, 4,
|
|
IDS_GLOBAL_STATUS, NetStatusToString(NetStatus));
|
|
|
|
// This isn't fatal.
|
|
RetVal = TRUE;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get a DC that's UP.
|
|
//
|
|
|
|
pTestedDc = GetUpTestedDc( TestedDomain );
|
|
|
|
if ( pTestedDc == NULL ) {
|
|
AddMessageToList( &pResults->Trust.lmsgOutput, Nd_Verbose,
|
|
IDS_TRUST_NODC_UP, TestedDomain->PrintableDomainName);
|
|
PrintGuruMessage2(" '%ws': No DCs are up (Cannot run test).\n",
|
|
TestedDomain->PrintableDomainName );
|
|
PrintGuru( NetStatus, DSGETDC_GURU );
|
|
// This isn't fatal.
|
|
RetVal = TRUE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
//
|
|
// Connect to the SAM server
|
|
//
|
|
|
|
Status = NettestSamConnect(
|
|
pParams,
|
|
pTestedDc->ComputerName,
|
|
&LocalSamHandle );
|
|
|
|
if ( !NT_SUCCESS(Status)) {
|
|
if ( Status == STATUS_ACCESS_DENIED ) {
|
|
//IDS_TRUST_NO_ACCESS " [WARNING] Don't have access to test your domain sid for domain '%ws'. [Test skipped]\n"
|
|
AddMessageToList( &pResults->Trust.lmsgOutput, Nd_Verbose,
|
|
IDS_TRUST_NO_ACCESS, TestedDomain->PrintableDomainName );
|
|
}
|
|
// This isn't fatal.
|
|
RetVal = TRUE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
//
|
|
// Open the domain.
|
|
// Ask for no access to avoid access denied.
|
|
//
|
|
|
|
Status = SamOpenDomain( LocalSamHandle,
|
|
0,
|
|
pResults->Global.pMemberDomain->DomainSid,
|
|
&DomainHandle );
|
|
|
|
if ( Status == STATUS_NO_SUCH_DOMAIN ) {
|
|
AddIMessageToList(&pResults->Trust.lmsgOutput, Nd_Quiet, 0, IDS_TRUST_WRONGSID, TestedDomain->PrintableDomainName );
|
|
RetVal = FALSE;
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
if ( !NT_SUCCESS( Status ) ) {
|
|
AddIMessageToList(&pResults->Trust.lmsgOutput, Nd_Quiet, 0, IDS_TRUST_FAILED_SAMOPEN, pTestedDc->ComputerName );
|
|
RetVal = FALSE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
//
|
|
// Cleanup locally used resources
|
|
//
|
|
Cleanup:
|
|
if ( DomainHandle != NULL ) {
|
|
(VOID) SamCloseHandle( DomainHandle );
|
|
}
|
|
|
|
if ( LocalSamHandle != NULL ) {
|
|
(VOID) SamCloseHandle( LocalSamHandle );
|
|
}
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
|