windows-nt/Source/XPSP1/NT/net/diagnostics/netdiag/dsgetdc.c
2020-09-26 16:20:57 +08:00

779 lines
19 KiB
C

//++
//
// Copyright (C) Microsoft Corporation, 1987 - 1999
//
// Module Name:
//
// dsgetdc.c
//
// Abstract:
//
// Queries into network drivers
//
// Author:
//
// Anilth - 4-20-1998
//
// Environment:
//
// User mode only.
// Contains NT-specific code.
//
// Revision History:
//
//--
#include "precomp.h"
#include "objbase.h"
VOID PrintDsGetDcName(IN NETDIAG_RESULT *pResults,
IN OUT PLIST_ENTRY plmsgOutput,
IN PDOMAIN_CONTROLLER_INFOW DomainControllerInfo);
NET_API_STATUS SetPrimaryGuid(IN GUID *GuidToSet);
HRESULT
DsGetDcTest(NETDIAG_PARAMS* pParams, NETDIAG_RESULT* pResults)
/*++
Routine Description:
Ensure that we can find domain controllers
Arguments:
None.
Return Value:
TRUE: Test suceeded.
FALSE: Test failed
--*/
{
NET_API_STATUS NetStatus;
NET_API_STATUS LocalNetStatus;
BOOL RetVal = TRUE;
HRESULT hr = hrOK;
LPTSTR pszDcType;
PTESTED_DOMAIN pTestedDomain = (PTESTED_DOMAIN) pParams->pDomain;
PDOMAIN_CONTROLLER_INFOW LocalDomainControllerInfo = NULL;
//if the machine is a member machine or DC, DsGetDc Test will get called.
//Otherwise, this test will be skipped
pResults->DsGetDc.fPerformed = TRUE;
//the DsGetDc test will be called for every domain, but we only want to initialize
//the message list once.
if(pResults->DsGetDc.lmsgOutput.Flink == NULL)
InitializeListHead(&pResults->DsGetDc.lmsgOutput);
PrintStatusMessage(pParams, 4, IDS_DSGETDC_STATUS_MSG);
//
// Find a generic DC
//
PrintStatusMessage(pParams, 4, IDS_DSGETDC_STATUS_DC);
pszDcType = LoadAndAllocString(IDS_DCTYPE_DC);
NetStatus = DoDsGetDcName( pParams,
pResults,
&pResults->DsGetDc.lmsgOutput,
pTestedDomain,
DS_DIRECTORY_SERVICE_PREFERRED,
pszDcType, //_T("DC"),
TRUE,
&pTestedDomain->DcInfo );
Free(pszDcType);
pTestedDomain->fTriedToFindDcInfo = TRUE;
if ( NetStatus != NO_ERROR ) {
hr = S_FALSE;
goto Error;
}
//
// Find a PDC
// (Failure isn't fatal.)
//
PrintStatusMessage(pParams, 4, IDS_DSGETDC_STATUS_PDC);
pszDcType = LoadAndAllocString(IDS_DCTYPE_PDC);
LocalNetStatus = DoDsGetDcName(pParams,
pResults,
&pResults->DsGetDc.lmsgOutput,
pTestedDomain,
DS_PDC_REQUIRED,
pszDcType, //_T("PDC"),
FALSE,
&LocalDomainControllerInfo );
Free(pszDcType);
if ( LocalNetStatus == NO_ERROR )
{
if ( LocalDomainControllerInfo != NULL )
{
NetApiBufferFree( LocalDomainControllerInfo );
LocalDomainControllerInfo = NULL;
}
}
//
// Find an NT 5 DC
// (Failure isn't fatal.)
//
PrintStatusMessage(pParams, 4, IDS_DSGETDC_STATUS_NT5DC);
pszDcType = LoadAndAllocString(IDS_DCTYPE_W2K_DC);
LocalNetStatus = DoDsGetDcName(pParams,
pResults,
&pResults->DsGetDc.lmsgOutput,
pTestedDomain,
DS_DIRECTORY_SERVICE_REQUIRED,
pszDcType, //_T("Windows 2000 DC"),
FALSE,
&LocalDomainControllerInfo );
Free(pszDcType);
if ( LocalNetStatus == NO_ERROR )
{
if ( LocalDomainControllerInfo != NULL )
{
NetApiBufferFree( LocalDomainControllerInfo );
LocalDomainControllerInfo = NULL;
}
}
//
// Ensure the returned domain GUID is the domain GUID stored in the LSA
//
if ( pTestedDomain == pResults->Global.pMemberDomain )
{
if ( !IsEqualGUID( &pResults->Global.pPrimaryDomainInfo->DomainGuid, &NlDcZeroGuid ) &&
!IsEqualGUID( &pTestedDomain->DcInfo->DomainGuid, &NlDcZeroGuid ) &&
!IsEqualGUID( &pResults->Global.pPrimaryDomainInfo->DomainGuid,
&pTestedDomain->DcInfo->DomainGuid ) )
{
// Need to convert the two GUIDS
WCHAR swzGuid1[64];
WCHAR swzGuid2[64];
StringFromGUID2(&pResults->Global.pPrimaryDomainInfo->DomainGuid,
swzGuid1,
DimensionOf(swzGuid1));
StringFromGUID2(&pTestedDomain->DcInfo->DomainGuid,
swzGuid2,
DimensionOf(swzGuid2));
// " [FATAL] Your machine thinks the domain GUID of domain '%ws' is\n '"
// "' but \n '%ws' thinks it is\n '"
AddMessageToList(&pResults->DsGetDc.lmsgOutput,
Nd_Quiet,
IDS_DSGETDC_FATAL_GUID,
pResults->Global.pPrimaryDomainInfo->DomainNameFlat,
swzGuid1,
pTestedDomain->DcInfo->DomainControllerName,
swzGuid2);
hr = S_FALSE;
//
// Attempt to fix the problem.
//
if ( !pParams->fFixProblems )
{
// "\nConsider running 'nettest /fix' to try to fix this problem\n"
AddMessageToList( &pResults->DsGetDc.lmsgOutput, Nd_Quiet, IDS_DSGETDC_13206 );
}
else
{
NetStatus = SetPrimaryGuid( &pTestedDomain->DcInfo->DomainGuid );
if ( NetStatus != NO_ERROR )
{
if ( NetStatus == ERROR_ACCESS_DENIED )
{
// "\nCannot fix domain GUID since you are not an administrator. Leave then rejoin the domain.\n"
AddMessageToList( &pResults->DsGetDc.lmsgOutput, Nd_Quiet, IDS_DSGETDC_13207 );
}
else
{
// " [FATAL] Failed to fix Domain Guid. [%s]\n"
AddMessageToList( &pResults->DsGetDc.lmsgOutput, Nd_Quiet,
IDS_DSGETDC_13208, NetStatusToString(NetStatus) );
}
}
else
{
// "\nFixed domain GUID. Reboot then run 'nettest' again to ensure everything is working.\n"
AddMessageToList( &pResults->DsGetDc.lmsgOutput, Nd_Quiet, IDS_DSGETDC_13209 );
}
}
}
}
Error:
//$REVIEW (nsun 10/05/98) CliffV deleted DCNameClose()
//DCNameClose();
pResults->DsGetDc.hr = hr;
return hr;
}
VOID
PrintDsGetDcName(
IN NETDIAG_RESULT *pResults,
IN OUT PLIST_ENTRY plmsgOutput,
IN PDOMAIN_CONTROLLER_INFOW DomainControllerInfo
)
/*++
Routine Description:
Prints the information returned from DsGetDcName
Arguments:
DomainControllerInfo - Information to print
Return Value:
None.
--*/
{
// " DC: %ws\n"
AddMessageToList( plmsgOutput,
Nd_Quiet,
IDS_DSGETDC_13210,
DomainControllerInfo->DomainControllerName );
// " Address: %ws\n"
AddMessageToList( plmsgOutput,
Nd_Quiet,
IDS_DSGETDC_13211,
DomainControllerInfo->DomainControllerAddress );
if ( !IsEqualGUID( &DomainControllerInfo->DomainGuid, &NlDcZeroGuid) )
{
WCHAR swzGuid[64];
StringFromGUID2(&DomainControllerInfo->DomainGuid,
swzGuid,
DimensionOf(swzGuid));
// " Domain Guid . . . . . . : %ws\n"
AddMessageToList( plmsgOutput,
Nd_Quiet,
IDS_DSGETDC_13212,
swzGuid);
}
if ( DomainControllerInfo->DomainName != NULL )
{
// " Dom Name: %ws\n"
AddMessageToList( plmsgOutput,
Nd_Quiet,
IDS_DSGETDC_13214,
DomainControllerInfo->DomainName );
}
if ( DomainControllerInfo->DnsForestName != NULL )
{
// " Forest Name: %ws\n"
AddMessageToList( plmsgOutput,
Nd_Quiet,
IDS_DSGETDC_13215,
DomainControllerInfo->DnsForestName );
}
if ( DomainControllerInfo->DcSiteName != NULL )
{
// " Dc Site Name: %ws\n"
AddMessageToList( plmsgOutput,
Nd_Quiet,
IDS_DSGETDC_13216,
DomainControllerInfo->DcSiteName );
}
if ( DomainControllerInfo->ClientSiteName != NULL )
{
// " Our Site Name: %ws\n"
AddMessageToList( plmsgOutput,
Nd_Quiet,
IDS_DSGETDC_13217,
DomainControllerInfo->ClientSiteName );
}
if ( DomainControllerInfo->Flags )
{
ULONG LocalFlags = DomainControllerInfo->Flags;
// " Flags:"
AddMessageToList( plmsgOutput,
Nd_Quiet,
IDS_DSGETDC_13218 );
if ( LocalFlags & DS_PDC_FLAG )
{
// " PDC"
AddMessageToList( plmsgOutput,
Nd_Quiet,
(LocalFlags & DS_DS_FLAG) ? IDS_DSGETDC_13219 : IDS_DSGETDC_NT4_PDC);
LocalFlags &= ~DS_PDC_FLAG;
}
if ( LocalFlags & DS_GC_FLAG ) {
//IDS_DSGETDC_13220 " GC"
AddMessageToList( plmsgOutput,
Nd_Quiet,
IDS_DSGETDC_13220);
LocalFlags &= ~DS_GC_FLAG;
}
if ( LocalFlags & DS_DS_FLAG ) {
//IDS_DSGETDC_13221 " DS"
AddMessageToList( plmsgOutput,
Nd_Quiet,
IDS_DSGETDC_13221);
LocalFlags &= ~DS_DS_FLAG;
}
if ( LocalFlags & DS_KDC_FLAG ) {
//IDS_DSGETDC_13222 " KDC"
AddMessageToList( plmsgOutput,
Nd_Quiet,
IDS_DSGETDC_13222);
LocalFlags &= ~DS_KDC_FLAG;
}
if ( LocalFlags & DS_TIMESERV_FLAG ) {
//IDS_DSGETDC_13223 " TIMESERV"
AddMessageToList( plmsgOutput,
Nd_Quiet,
IDS_DSGETDC_13223);
LocalFlags &= ~DS_TIMESERV_FLAG;
}
if ( LocalFlags & DS_GOOD_TIMESERV_FLAG ) {
//IDS_DSGETDC_13224 " GTIMESERV"
AddMessageToList( plmsgOutput,
Nd_Quiet,
IDS_DSGETDC_13224);
LocalFlags &= ~DS_GOOD_TIMESERV_FLAG;
}
if ( LocalFlags & DS_WRITABLE_FLAG ) {
//IDS_DSGETDC_13225 " WRITABLE"
AddMessageToList( plmsgOutput,
Nd_Quiet,
IDS_DSGETDC_13225);
LocalFlags &= ~DS_WRITABLE_FLAG;
}
if ( LocalFlags & DS_DNS_CONTROLLER_FLAG ) {
//IDS_DSGETDC_13226 " DNS_DC"
AddMessageToList( plmsgOutput,
Nd_Quiet,
IDS_DSGETDC_13226);
LocalFlags &= ~DS_DNS_CONTROLLER_FLAG;
}
if ( LocalFlags & DS_DNS_DOMAIN_FLAG ) {
//IDS_DSGETDC_13227 " DNS_DOMAIN"
AddMessageToList( plmsgOutput,
Nd_Quiet,
IDS_DSGETDC_13227);
LocalFlags &= ~DS_DNS_DOMAIN_FLAG;
}
if ( LocalFlags & DS_DNS_FOREST_FLAG ) {
//IDS_DSGETDC_13228 " DNS_FOREST"
AddMessageToList( plmsgOutput,
Nd_Quiet,
IDS_DSGETDC_13228);
LocalFlags &= ~DS_DNS_FOREST_FLAG;
}
if ( LocalFlags & DS_CLOSEST_FLAG ) {
//IDS_DSGETDC_13229 " CLOSE_SITE"
AddMessageToList( plmsgOutput,
Nd_Quiet,
IDS_DSGETDC_13229);
LocalFlags &= ~DS_CLOSEST_FLAG;
}
if ( LocalFlags != 0 ) {
//IDS_DSGETDC_13230 " 0x%lX"
AddMessageToList( plmsgOutput,
Nd_Quiet,
IDS_DSGETDC_13230,
LocalFlags);
}
//IDS_DSGETDC_13231 "\n"
AddMessageToList( plmsgOutput,
Nd_Quiet,
IDS_DSGETDC_13231);
}
}
NET_API_STATUS
DoDsGetDcName(IN NETDIAG_PARAMS *pParams,
IN OUT NETDIAG_RESULT *pResults,
OUT PLIST_ENTRY plmsgOutput,
IN PTESTED_DOMAIN pTestedDomain,
IN DWORD Flags,
IN LPTSTR pszDcType,
IN BOOLEAN IsFatal,
OUT PDOMAIN_CONTROLLER_INFOW *DomainControllerInfo
)
/*++
Routine Description:
Does a DsGetDcName
Arguments:
plmsgOutput - The message list to dump output
pTestedDomain - Domain to test
Flags - Flags to pass to DsGetDcName
pszDcType - English description of Flags
IsFatal - True if failure is fatal
DomainControllerInfo - Return Domain Controller information
Return Value:
Status of the operation.
--*/
{
NET_API_STATUS NetStatus;
PDOMAIN_CONTROLLER_INFOW LocalDomainControllerInfo = NULL;
LPSTR Severity;
//
// Initialization
//
if ( IsFatal ) {
Severity = "[FATAL]";
} else {
Severity = "[WARNING]";
}
if ( pParams->fReallyVerbose )
{
// "\n Find %s in domain '%ws':\n"
AddMessageToList( plmsgOutput, Nd_ReallyVerbose, IDS_DSGETDC_13232, pszDcType, pTestedDomain->PrintableDomainName );
}
//
// Find a DC in the domain.
// Use the DsGetDcName built into nettest.
//
NetStatus = GetADc( pParams,
pResults,
plmsgOutput,
// Commented out to port to Source Depot - smanda
#ifdef SLM_TREE
NettestDsGetDcNameW,
#else
DsGetDcNameW,
#endif
pTestedDomain,
Flags,
DomainControllerInfo );
if ( NetStatus != NO_ERROR )
{
// " %s Cannot find %s in domain '%ws'. [%s]\n"
AddMessageToList( plmsgOutput,
Nd_Quiet,
IDS_DSGETDC_13233,
Severity,
pszDcType,
pTestedDomain->PrintableDomainName,
NetStatusToString(NetStatus));
if ( NetStatus == ERROR_NO_SUCH_DOMAIN ) {
if ( Flags & DS_DIRECTORY_SERVICE_REQUIRED )
{
// "\n This isn't a problem if domain '%ws' does not have any NT 5.0 DCs.\n"
AddMessageToList( plmsgOutput,
Nd_Quiet,
IDS_DSGETDC_13234,
pTestedDomain->PrintableDomainName );
}
else if ( Flags & DS_PDC_REQUIRED )
{
PrintGuruMessage2(" If the PDC for domain '%ws' is up, ", TestedDomain->PrintableDomainName );
PrintGuru( 0, DSGETDC_GURU );
} else
{
PrintGuruMessage3(" If any %s for domain '%ws' is up, ", DcType, TestedDomain->PrintableDomainName );
PrintGuru( 0, DSGETDC_GURU );
}
}
else
{
PrintGuru( NetStatus, DSGETDC_GURU );
}
//
// If that worked,
// try again through netlogon this time.
//
}
else
{
if (pParams->fReallyVerbose )
{
// " Found this %s in domain '%ws':\n"
AddMessageToList( plmsgOutput,
Nd_ReallyVerbose,
IDS_DSGETDC_13235,
pszDcType,
pTestedDomain->PrintableDomainName );
PrintDsGetDcName( pResults, plmsgOutput, *DomainControllerInfo );
}
else if ( pParams->fVerbose )
{
// " Found %s '%ws' in domain '%ws'.\n"
AddMessageToList( plmsgOutput,
Nd_Verbose,
IDS_DSGETDC_13236,
pszDcType,
(*DomainControllerInfo)->DomainControllerName,
pTestedDomain->PrintableDomainName );
}
if ( ((*DomainControllerInfo)->Flags & (DS_DS_FLAG|DS_KDC_FLAG)) == DS_DS_FLAG )
{
// " %s: KDC is not running on NT 5 DC '%ws' in domain '%ws'."
AddMessageToList( plmsgOutput,
Nd_Quiet,
IDS_DSGETDC_13237,
Severity,
(*DomainControllerInfo)->DomainControllerName,
pTestedDomain->PrintableDomainName );
}
//
// If netlogon is running,
// try it again using the netlogon service.
//
if ( pResults->Global.fNetlogonIsRunning )
{
NetStatus = GetADc( pParams,
pResults,
plmsgOutput,
DsGetDcNameW,
pTestedDomain,
Flags,
&LocalDomainControllerInfo );
if ( NetStatus != NO_ERROR )
{
// " %s: Netlogon cannot find %s in domain '%ws'. [%s]\n"
AddMessageToList( plmsgOutput,
Nd_Quiet,
IDS_DSGETDC_13238,
Severity,
pszDcType,
pTestedDomain->PrintableDomainName,
NetStatusToString(NetStatus));
//
// If that worked,
// sanity check the returned DC.
//
}
else
{
if ( (LocalDomainControllerInfo->Flags & (DS_DS_FLAG|DS_KDC_FLAG)) == DS_DS_FLAG )
{
// " %s: KDC is not running on NT 5 DC '%ws' in domain '%ws'."
AddMessageToList( plmsgOutput,
Nd_Quiet,
IDS_DSGETDC_13239,
Severity,
LocalDomainControllerInfo->DomainControllerName,
pTestedDomain->PrintableDomainName );
}
}
}
}
if ( LocalDomainControllerInfo != NULL ) {
NetApiBufferFree( LocalDomainControllerInfo );
LocalDomainControllerInfo = NULL;
}
return NetStatus;
}
NET_API_STATUS
SetPrimaryGuid(
IN GUID *GuidToSet
)
/*++
Routine Description:
Set the primary GUID to the specified value.
Arguments:
GuidToSet - Guid to set as the primary GUID
Return Value:
NET_API_STATUS - NERR_Success or reason for failure.
--*/
{
NET_API_STATUS NetStatus;
NTSTATUS Status;
LSA_HANDLE PolicyHandle = NULL;
PPOLICY_DNS_DOMAIN_INFO PrimaryDomainInfo = NULL;
OBJECT_ATTRIBUTES ObjAttributes;
//
// Open a handle to the LSA.
//
InitializeObjectAttributes(
&ObjAttributes,
NULL,
0L,
NULL,
NULL
);
Status = LsaOpenPolicy(
NULL,
&ObjAttributes,
POLICY_VIEW_LOCAL_INFORMATION |
POLICY_TRUST_ADMIN,
&PolicyHandle
);
if (! NT_SUCCESS(Status)) {
NetStatus = NetpNtStatusToApiStatus(Status);
goto Cleanup;
}
//
// Get the name of the primary domain from LSA
//
Status = LsaQueryInformationPolicy(
PolicyHandle,
PolicyDnsDomainInformation,
(PVOID *) &PrimaryDomainInfo
);
if (! NT_SUCCESS(Status)) {
NetStatus = NetpNtStatusToApiStatus(Status);
goto Cleanup;
}
//
// Set the new GUID of the primary domain into the LSA
//
PrimaryDomainInfo->DomainGuid = *GuidToSet;
Status = LsaSetInformationPolicy(
PolicyHandle,
PolicyDnsDomainInformation,
(PVOID) PrimaryDomainInfo
);
if (! NT_SUCCESS(Status)) {
NetStatus = NetpNtStatusToApiStatus(Status);
goto Cleanup;
}
NetStatus = NO_ERROR;
Cleanup:
if ( PrimaryDomainInfo != NULL ) {
(void) LsaFreeMemory((PVOID) PrimaryDomainInfo);
}
if ( PolicyHandle != NULL ) {
(void) LsaClose(PolicyHandle);
}
return NetStatus;
}
/*!--------------------------------------------------------------------------
DsGetDcGlobalPrint
-
Author: KennT
---------------------------------------------------------------------------*/
void DsGetDcGlobalPrint( NETDIAG_PARAMS* pParams,
NETDIAG_RESULT* pResults)
{
if (pParams->fVerbose || !FHrOK(pResults->DsGetDc.hr))
{
PrintNewLine(pParams, 2);
PrintTestTitleResult(pParams, IDS_DSGETDC_LONG, IDS_DSGETDC_SHORT, pResults->DsGetDc.fPerformed,
pResults->DsGetDc.hr, 0);
if (pParams->fReallyVerbose || !FHrOK(pResults->DsGetDc.hr))
PrintMessageList(pParams, &pResults->DsGetDc.lmsgOutput);
}
}
/*!--------------------------------------------------------------------------
DsGetDcPerInterfacePrint
-
Author: KennT
---------------------------------------------------------------------------*/
void DsGetDcPerInterfacePrint( NETDIAG_PARAMS* pParams,
NETDIAG_RESULT* pResults,
INTERFACE_RESULT *pInterfaceResults)
{
// no per-interface results
}
/*!--------------------------------------------------------------------------
DsGetDcCleanup
-
Author: KennT
---------------------------------------------------------------------------*/
void DsGetDcCleanup( NETDIAG_PARAMS* pParams, NETDIAG_RESULT* pResults)
{
MessageListCleanUp(&pResults->DsGetDc.lmsgOutput);
}