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.
 
 
 
 
 
 

439 lines
13 KiB

//+----------------------------------------------------------------------------
//
// Copyright (C) 2000, Microsoft Corporation
//
// File: DfsTrustedDomain.cxx
//
// Contents: implements the trusted domain
//
// Classes: DfsTrustedDomain
//
// History: Apr. 8 2000, Author: udayh
//
//-----------------------------------------------------------------------------
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <windowsx.h>
#include <ntsam.h>
#include <dsgetdc.h>
#include <lmcons.h>
#include <lmapibuf.h>
#include <lmaccess.h>
#include <string.h>
#include <tchar.h>
#include <stdarg.h>
#include <process.h>
#include <ole2.h>
#include <ntdsapi.h>
#include "DfsReferralData.hxx"
#include "DfsTrustedDomain.hxx"
#include "DfsReplica.hxx"
//
// logging specific includes
//
#include "DfsTrustedDomain.tmh"
//+-------------------------------------------------------------------------
//
// Function: GetDcReferralData - get the referral data
//
// Arguments: ppReferralData - the referral data for this instance
// pCacheHit - did we find it already loaded?
//
// Returns: Status
// ERROR_SUCCESS if we could get the referral data
// error status otherwise.
//
//
// Description: This routine returns a reference DfsReferralDAta
// If one does not already exist in this class instance,
// we create a new one. If someone is in the process
// of loading the referral, we wait on the event in
// the referral data which gets signalled when the thread
// responsible for loading is done with the load.
//
//--------------------------------------------------------------------------
DFSSTATUS
DfsTrustedDomain::GetDcReferralData(
OUT DfsReferralData **ppReferralData,
OUT BOOLEAN *pCacheHit )
{
DfsReferralData *pRefData = NULL;
DFSSTATUS Status = STATUS_SUCCESS;
if (_DomainName.Length == 0)
{
return ERROR_INVALID_PARAMETER;
}
*pCacheHit = FALSE;
Status = AcquireLock();
if ( Status != STATUS_SUCCESS )
{
return Status;
}
// First see if we may need to do a reload.
if (_LoadState == DfsTrustedDomainDcLoadFailed &&
IsTimeToRetry())
{
ASSERT(_pDcReferralData == NULL);
_LoadState = DfsTrustedDomainDcNotLoaded;
}
//
// WE take difference action depending on the load state.
//
switch ( _LoadState )
{
case DfsTrustedDomainDcLoaded:
DFS_TRACE_LOW(REFERRAL_SERVER, " Get Referral Data: Cache hit\n");
//
// we are dealing with a loaded instance. Just acquire a reference
// and return the loaded referral data.
//
ASSERT (_pDcReferralData != NULL);
pRefData = _pDcReferralData;
pRefData->AcquireReference();
ReleaseLock();
*pCacheHit = TRUE;
*ppReferralData = pRefData;
break;
case DfsTrustedDomainDcNotLoaded:
//
// The dc info is not loaded. Make sure that the referral data is
// indeed empty. Create a new instance of the referral data
// and set the state to load in progress.
ASSERT(_pDcReferralData == NULL);
DFS_TRACE_NORM(REFERRAL_SERVER, " Get Referral Data: not loaded\n");
_pDcReferralData = new DfsReferralData( &Status );
if ( _pDcReferralData != NULL )
{
if(Status == ERROR_SUCCESS)
{
_LoadState = DfsTrustedDomainDcLoadInProgress;
//
// Acquire a reference on the new referral data, since we
// have to return a referenced referral data to the caller.
//
pRefData = _pDcReferralData;
pRefData->AcquireReference();
}
else
{
_pDcReferralData->ReleaseReference();
_pDcReferralData = NULL;
}
} else
{
Status = ERROR_NOT_ENOUGH_MEMORY;
}
//
// We no longer need the lock. We have allocate the referral
// data and marked the state accordingly. No other thread can
// interfere with our load now.
//
ReleaseLock();
//
// Now we load the referral data, and save the status of the
// load in both our load status as well as the load status
// in the referral data.
// If the load was successful, we add this to the loaded list
// of referral data that can be scavenged later. We set the load
// state to loaded, and signal the event so that all waiting
// threads can now be woken up.
//
if ( Status == ERROR_SUCCESS )
{
_pDcReferralData->DoSiteCosting = (BOOLEAN)DfsCheckSiteCostingEnabled();
Status = LoadDcReferralData( _pDcReferralData );
_LoadStatus = Status;
_RetryFailedLoadTimeout = 0;
_pDcReferralData->LoadStatus = Status;
if ( Status == ERROR_SUCCESS )
{
_LoadState = DfsTrustedDomainDcLoaded;
*ppReferralData = pRefData;
pRefData->Signal();
} else
{
_LoadState = DfsTrustedDomainDcLoadFailed;
_RetryFailedLoadTimeout = GetTickCount();
pRefData->Signal();
(VOID)RemoveDcReferralData( pRefData, NULL );
DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER,
"DomainDC load failed for %wZ, LoadStatus %x, Status %x\n",
GetDomainName(),
_LoadStatus,
Status );
}
}
break;
case DfsTrustedDomainDcLoadInProgress:
//
// The load is in progress. We acquire a reference on the
// referral data being loaded and wait for the event in the
// referral data to be signalled. The return status of the wait
// indicates if we can return the referral data or we fail
// this request with an error.
//
DFS_TRACE_NORM(REFERRAL_SERVER, " Get Referral Data: load in progress\n");
ASSERT(_pDcReferralData != NULL);
pRefData = _pDcReferralData;
pRefData->AcquireReference();
ReleaseLock();
DFS_TRACE_NORM(REFERRAL_SERVER, "Thread: Waiting for referral load\n");
Status = pRefData->Wait();
if ( Status == ERROR_SUCCESS )
{
*ppReferralData = pRefData;
} else
{
pRefData->ReleaseReference();
}
DFS_TRACE_NORM(REFERRAL_SERVER, " Get Referral Data: load in progress done\n");
break;
case DfsTrustedDomainDcLoadFailed:
//
// The Load failed. REturn error. We need to setup a time
// after which we need to reattempt the load.
//
Status = _LoadStatus;
ReleaseLock();
*ppReferralData = NULL;
break;
default:
//
// We should never get here. Its an invalid state.
//
ASSERT(TRUE);
Status = ERROR_INVALID_STATE;
ReleaseLock();
break;
}
ASSERT((Status != ERROR_SUCCESS) || (*ppReferralData != NULL));
return Status;
}
DFSSTATUS
DfsTrustedDomain::RemoveDcReferralData(
DfsReferralData *pRemoveReferralData,
PBOOLEAN pRemoved )
{
DFSSTATUS Status = ERROR_SUCCESS;
DfsReferralData *pRefData = NULL;
//
// Get the exclusive lock on this instance
//
if (pRemoved != NULL)
{
*pRemoved = FALSE;
}
AcquireLock();
//
// make sure _LoadState indicates that it is loaded.
// Set the referralData to null, and state to NotLoaded.
//
if (_LoadState == DfsTrustedDomainDcLoaded || _LoadState == DfsTrustedDomainDcLoadFailed)
{
pRefData = _pDcReferralData;
if ( (pRemoveReferralData == NULL) ||
(pRemoveReferralData == pRefData) )
{
_pDcReferralData = NULL;
_LoadState = (_LoadState == DfsTrustedDomainDcLoaded) ?
DfsTrustedDomainDcNotLoaded : DfsTrustedDomainDcLoadFailed;
}
else {
pRefData = NULL;
}
}
ReleaseLock();
//
// Release reference on the referral data. This is the reference
// we had taken when we had cached the referral data here.
//
if (pRefData != NULL)
{
pRefData->ReleaseReference();
if (pRemoved != NULL)
{
*pRemoved = TRUE;
}
}
return Status;
}
DFSSTATUS
DfsTrustedDomain::LoadDcReferralData(
IN DfsReferralData *pReferralData )
{
DFSSTATUS Status;
PDS_DOMAIN_CONTROLLER_INFO_1 pDsDomainControllerInfo1 = NULL;
HANDLE HandleToDs = NULL;
ULONG NameCount = 0, Index;
ULONG DsDcCount = 0;
ULONG UseIndex = 0;
BOOLEAN CacheHit = FALSE;
LPWSTR DomainController = NULL;
//
// we have a problem that DsBind fails when going across forests
// for netbios domains as local system.
// So we bind to the DNS domain name only for cross forest domains,
// this information is stored by UseBindDomain boolean.
//
Status = DsBind(DomainController,
_UseBindDomain ? _BindDomainName.Buffer : _DomainName.Buffer,
&HandleToDs);
DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "DfsTrustedDomain DsBind Status %d\n",
Status);
if (Status == ERROR_SUCCESS)
{
Status = DsGetDomainControllerInfo( HandleToDs,
_DomainName.Buffer,
1,
&NameCount,
(PVOID *)(&pDsDomainControllerInfo1));
DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "DfsTrustedDomain DsGetDomainControllerInfo Status %d\n",
Status);
DsUnBind( &HandleToDs);
}
if (Status == ERROR_SUCCESS)
{
for (Index = 0; Index < NameCount; Index++)
{
if (pDsDomainControllerInfo1[Index].fDsEnabled == TRUE)
{
DsDcCount++;
}
}
if (DsDcCount > 0)
{
pReferralData->pReplicas = new DfsReplica[ DsDcCount ];
if (pReferralData->pReplicas == NULL)
{
Status = ERROR_NOT_ENOUGH_MEMORY;
}
else
{
pReferralData->ReplicaCount = DsDcCount;
}
}
for (Index = 0; ((Index < NameCount) && (Status == ERROR_SUCCESS)); Index++)
{
LPWSTR UseName;
CacheHit = FALSE;
if (pDsDomainControllerInfo1[Index].fDsEnabled != TRUE)
{
continue;
}
if (_Netbios == TRUE)
{
UseName = pDsDomainControllerInfo1[Index].NetbiosName;
}
else
{
UseName = pDsDomainControllerInfo1[Index].DnsHostName;
if (UseName == NULL)
{
UseName = pDsDomainControllerInfo1[Index].NetbiosName;
DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "DfsDomainInformation DNS Name is NULL. Using Netbios =%ws Status %d\n",
UseName, Status);
}
}
if (UseName != NULL)
{
UNICODE_STRING TargetName;
Status = DfsRtlInitUnicodeStringEx(&TargetName, UseName);
if(Status == ERROR_SUCCESS)
{
Status = (&pReferralData->pReplicas[ UseIndex ])->SetTargetServer( &TargetName, &CacheHit );
DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "DfsDomainInformation SetTargetServer=%wZ Status %d\n",
&TargetName, Status);
}
UseIndex++;
}
}
DsFreeDomainControllerInfo( 1,
NameCount,
pDsDomainControllerInfo1);
}
return Status;
}