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.
 
 
 
 
 
 

432 lines
12 KiB

#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <windef.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include "dfsgeneric.hxx"
#include "dfsinit.hxx"
#include "dsgetdc.h"
#include "lm.h"
#include <dsrole.h>
#include <DfsReferralData.h>
#include <DfsReferral.hxx>
#include <dfsheader.h>
#include <Dfsumr.h>
#include <winsock2.h>
#include <DfsSiteCache.hxx>
#include <DfsSiteCostCache.hxx>
#include <DfsSiteNameSupport.hxx>
#include <DfsSite.hxx>
//
// logging includes.
//
#include "DfsSite.tmh"
#define _Dfs_LocalAddress 0x0100007f //localaddress (127.0.0.1)
//
// Given the sitename initialize this site.
// We'll also calculate the corresponding hashvalue
// for future use. The SiteCostCache for this site
// will be allocated also. It'll get populated as we get
// referrals.
//
DFSSTATUS
DfsSite::Initialize(
IN PUNICODE_STRING pSiteName)
{
DFSSTATUS Status = ERROR_SUCCESS;
//
// Copy the sitename. It's ok if this is NULL.
//
Status = DfsCreateUnicodeString(&_SiteName, pSiteName);
if (Status != ERROR_SUCCESS)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
// Pre-calculate that wonderful hash value.
CalcHash();
Status = DfsSiteCostSupport::DfsCreateSiteCostSupport( &_pSiteCostSupport );
return Status;
}
//
//
//
VOID
DfsSite::GetDefaultSiteCost(
DfsSite *DestinationSite,
PULONG pCost)
{
//
// If we are dealing with an empty sitename at either end,
// we err on the safe side.
//
*pCost = DFS_MAX_COST;
if ((IsEmptyString( DestinationSite->SiteNameString() ) == FALSE) &&
(IsEmptyString( _SiteName.Buffer ) == FALSE))
{
// If the sitenames are the same the cost is zero by definition.
if (DfsCompareSiteNames( &_SiteName, DestinationSite->SiteName() ) == 0)
{
*pCost = DFS_MIN_COST;
}
}
return;
}
//
// Given a target site, return its cost.
// We simply have to get it from the Cache.
// We return ERROR_NOT_FOUND if it's not there.
//
DFSSTATUS
DfsSite::GetRealSiteCost(
DfsSite *DestinationSite,
PULONG pCost)
{
DFSSTATUS Status = ERROR_SUCCESS;
ASSERT(DestinationSite);
DfsSiteCostCache *pCache = NULL;
ASSERT(_pSiteCostSupport != NULL);
if ((IsEmptyString( DestinationSite->SiteNameString() )) ||
(IsEmptyString( _SiteName.Buffer )))
{
*pCost = DFS_MAX_COST;
return Status;
}
Status = _pSiteCostSupport->Acquire( &pCache );
if (Status == ERROR_SUCCESS)
{
//
// Get the value from the cache if it's there.
// Else, it'll return NOT_FOUND.
//
Status = pCache->GetCost( DestinationSite, pCost );
_pSiteCostSupport->Release();
}
DFS_TRACE_LOW( REFERRAL, "GetCost Status 0x%x: From %ws to %ws, Cost = 0x%x\n",
Status, SiteNameString(), DestinationSite->SiteNameString(), *pCost );
return Status;
}
//
// Given the IpAddress, return a corresponding
// DfsSite. This is meant to always succeed.
//
VOID
DfsIpToDfsSite(
IN char * IpData,
IN ULONG IpLength,
IN USHORT IpFamily,
OUT DfsSite **ppSite)
{
DFSSTATUS Status = ERROR_SUCCESS;
LPWSTR *SiteNamesArray = NULL;
DWORD IpAddress = 0;
unsigned char *IpAddr = (unsigned char *)IpData;
PVOID pBufferToFree = NULL;
LPWSTR FoundSiteName = NULL;
DfsSite *pFoundSite = NULL;
CopyMemory(&IpAddress, IpAddr, sizeof(IpAddress));
//
// If this is local then we have it easy.
//
if ((IpAddress == _Dfs_LocalAddress) &&
(IpLength == 4))
{
Status = DsGetSiteName( NULL, &FoundSiteName );
if (Status == ERROR_SUCCESS)
{
pBufferToFree = (PVOID)FoundSiteName;
DFS_TRACE_LOW(REFERRAL, "IpToDfsSite: LOCAL IP maps to SiteName %ws\n",
FoundSiteName);
}
DFS_TRACE_ERROR_HIGH(Status, REFERRAL, "DsGetSiteName fails with Status 0x%x for LOCAL IP\n",
Status);
}
else
{
//
// Send in the IP Address to get the site name.
//
Status = DfsGetSiteNameFromIpAddress( IpData,
IpLength,
IpFamily,
&SiteNamesArray );
if ((Status == ERROR_SUCCESS) &&
(SiteNamesArray != NULL))
{
//
// We found the sitename. We only look at the first entry
// returned. We'll also create the hash entry for future use.
//
if (SiteNamesArray[0] != NULL)
{
FoundSiteName = SiteNamesArray[0];
}
pBufferToFree = (PVOID)SiteNamesArray;
}
DFS_TRACE_ERROR_HIGH(Status, REFERRAL, "DsGetSiteNameFromIpAddress fails with Status 0x%x for IP\n",
Status);
}
if (FoundSiteName != NULL)
{
//
// Get the DfsSite corresponding to this site name.
// If for any reason, including NOT_ENOUGH_MEMORY, this fails,
// we simply use our default dfssite (see below).
//
(VOID) DfsGetSiteBySiteName( FoundSiteName, &pFoundSite );
}
//
// Default DfsSite has a NULL site name, and knows of no site-cost to anybody.
// It is pre-created at startup time, so it's guaranteed to exist.
//
if (pFoundSite == NULL)
{
pFoundSite = DfsGetDefaultSite();
DFS_TRACE_LOW(REFERRAL, "IpToDfsSite: Using default Empty DfsSite for IP %d:%d:%d:%d\n",
IpAddr[0],
IpAddr[1],
IpAddr[2],
IpAddr[3]);
}
*ppSite = pFoundSite;
//
// We've made a copy, ok to free this array now.
//
if (pBufferToFree != NULL)
{
NetApiBufferFree( pBufferToFree );
}
}
//
// Given a sitename, return a referenced DfsSite.
//
DFSSTATUS
DfsGetSiteBySiteName(
LPWSTR SiteNameString,
DfsSite **ppSite)
{
DFSSTATUS Status = ERROR_SUCCESS;
DfsSite *pDfsSite = NULL;
PDFS_SITE_NAME_DATA pSiteNameData = NULL;
UNICODE_STRING SiteName;
do {
Status = DfsRtlInitUnicodeStringEx( &SiteName, SiteNameString );
if (Status != ERROR_SUCCESS)
{
break;
}
//
// Empty site names get the default site.
//
if (IsEmptyString( SiteNameString ))
{
*ppSite = DfsGetDefaultSite();
DFS_TRACE_LOW(REFERRAL, "SiteBySiteName:Using default Empty DfsSite for Empty sitename\n");
break;
}
//
// Look it up to see if we know about this site already.
//
pSiteNameData = (PDFS_SITE_NAME_DATA)DfsServerGlobalData.pSiteNameSupport->LookupIpInHash(
&SiteName );
if (pSiteNameData != NULL)
{
ASSERT( pSiteNameData->pDfsSite != NULL );
ASSERT( Status == ERROR_SUCCESS );
//
// take a new reference on this site we found before returning.
//
pSiteNameData->pDfsSite->AcquireReference();
*ppSite = pSiteNameData->pDfsSite;
//
// Release the reference we acquired during lookup.
// We have a reference to the DfsSite inside it anyway.
//
DfsServerGlobalData.pSiteNameSupport->ReleaseSiteNameData( pSiteNameData );
DFS_TRACE_LOW(REFERRAL, "SiteBySiteName: Cachehit for sitename %ws -> DfsSite %p\n",
SiteNameString, *ppSite);
break;
}
//
// We have to create a new DfsSite.
//
pDfsSite = new DfsSite;
if (pDfsSite == NULL)
{
Status = ERROR_NOT_ENOUGH_MEMORY;
DFS_TRACE_ERROR_LOW(Status, REFERRAL, "DfsSite->constructor failed with 0x%x for sitename %ws\n",
Status, SiteNameString);
break;
}
//
// Initialize the site name as well as its site-cost cache.
// This call will make a copy of the sitename we send.
//
Status = pDfsSite->Initialize( &SiteName );
if (Status != ERROR_SUCCESS)
{
DFS_TRACE_ERROR_HIGH(Status, REFERRAL, "DfsSite->Initialize failed with 0x%x for sitename %ws\n",
Status, SiteNameString);
break;
}
//
// Put this in the SiteName->DfsSite cache.
// This StoreSiteInCache method will take a reference on the
// DfsSite. We ignore the return status; we don't need
// to fail this call just because the hash insertion failed.
//
(VOID) DfsServerGlobalData.pSiteNameSupport->StoreSiteInCache( pDfsSite );
//
// We've already taken a reference on this DfsSite
// when it was created. So just return the pointer.
// The caller needs to make sure that it releases this
// reference when its done.
//
*ppSite = pDfsSite;
DFS_TRACE_LOW(REFERRAL, "SiteBySiteName ->StoreInCache: Created new DfsSite %p for site %ws\n",
*ppSite, SiteNameString );
} while (FALSE);
// Error path.
if (Status != ERROR_SUCCESS)
{
//
// We acquired this reference when we instantiated this.
// This will delete it if we actually created it.
//
if (pDfsSite != NULL)
{
pDfsSite->ReleaseReference();
}
*ppSite = NULL;
}
return Status;
}
//
// The following are callbacks for the SiteCost hashtable.
//
// The hash value was pre-calculated at the
// time we initialized the site name.
ULONG
DfsHashDfsSite(
IN PVOID pSite)
{
DfsSite *Site = (DfsSite *)pSite;
ASSERT(Site != NULL);
return Site->Hash();
}
// Compare two sites to see if their names match.
int
DfsCompareDfsSites(
void* pvKey1,
void* pvKey2)
{
PUNICODE_STRING Site1 = ((DfsSite *) pvKey1)->SiteName();
PUNICODE_STRING Site2 = ((DfsSite *) pvKey2)->SiteName();
if (Site1->Length == Site2->Length)
{
return RtlCompareUnicodeString( Site1, Site2, FALSE );
} else {
return (signed)Site1->Length - (signed)Site2->Length;
}
}
// Compare two sites to see if their names match.
int
DfsCompareSiteNames(
void* pvKey1,
void* pvKey2)
{
PUNICODE_STRING Site1 = (PUNICODE_STRING) pvKey1;
PUNICODE_STRING Site2 = (PUNICODE_STRING) pvKey2;
if (Site1->Length == Site2->Length)
{
return RtlCompareUnicodeString( Site1, Site2, FALSE );
} else {
return (signed)Site1->Length - (signed)Site2->Length;
}
}
// Allocate the cache data entry
PVOID
DfsAllocateHashData(ULONG Size )
{
PVOID RetValue = NULL;
if (Size)
{
RetValue = (PVOID) new BYTE[Size];
if (RetValue != NULL)
{
RtlZeroMemory( RetValue, Size );
}
}
return RetValue;
}
VOID
DfsDeallocateHashData(PVOID pPointer )
{
PDFS_SITE_COST_DATA pSiteStructure = (PDFS_SITE_COST_DATA)pPointer;
if (pSiteStructure)
{
delete [] (PBYTE)pSiteStructure;
}
}