//++ // // 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; }