|
|
#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; } }
|