|
|
//+----------------------------------------------------------------------------
//
// Copyright (C) 2000, Microsoft Corporation
//
// File: DfsADBlobRootFolder.cxx
//
// Contents: the Root DFS Folder class for ADBlob Store
//
// Classes: DfsADBlobRootFolder
//
// History: Dec. 8 2000, Author: udayh
// April 14 2001 Rohanp - Modified to use ADSI code
//
//-----------------------------------------------------------------------------
#include "DfsADBlobRootFolder.hxx"
#include "DfsReplica.hxx"
#include "lmdfs.h"
#include "dfserror.hxx"
#include "dfsmisc.h"
#include "dfsadsiapi.hxx"
#include "domaincontrollersupport.hxx"
#include "DfsSynchronizeRoots.hxx"
#if !defined(DFS_STORAGE_STATE_MASTER)
#define DFS_STORAGE_STATE_MASTER 0x0010
#endif
#if !defined(DFS_STORAGE_STATE_STANDBY)
#define DFS_STORAGE_STATE_STANDBY 0x0020
#endif
//
// logging specific includes
//
#include "DfsADBlobRootFolder.tmh"
//+----------------------------------------------------------------------------
//
// Class: DfsADBlobRootFolder
//
// Synopsis: This class implements The Dfs ADBlob root folder.
//
//-----------------------------------------------------------------------------
//+-------------------------------------------------------------------------
//
// Function: DfsADBlobRootFolder - constructor
//
// Arguments: NameContext - the dfs name context
// pLogicalShare - the logical share
// pParentStore - the parent store for this root.
// pStatus - the return status
//
// Returns: NONE
//
// Description: This routine initializes a ADBlobRootFolder instance
//
//--------------------------------------------------------------------------
DfsADBlobRootFolder::DfsADBlobRootFolder( LPWSTR NameContext, LPWSTR pRootRegistryNameString, PUNICODE_STRING pLogicalShare, PUNICODE_STRING pPhysicalShare, DfsADBlobStore *pParentStore, DFSSTATUS *pStatus ) : DfsRootFolder ( NameContext, pRootRegistryNameString, pLogicalShare, pPhysicalShare, DFS_OBJECT_TYPE_ADBLOB_ROOT_FOLDER, pStatus ) { DFSSTATUS Status = *pStatus;
_pBlobCache = NULL;
_pStore = pParentStore; if (_pStore != NULL) { _pStore->AcquireReference(); }
_RootFlavor = DFS_VOLUME_FLAVOR_AD_BLOB;
//
// If the namecontext that we are passed is an emptry string,
// then we are dealing with the referral server running on the root
// itself. We are required to ignore the name context for such
// roots during lookups, so that aliasing works. (Aliasing is where
// someone may access the root with an aliased machine name or ip
// address)
//
if (Status == ERROR_SUCCESS) { if (IsEmptyString(NameContext) == TRUE) { SetIgnoreNameContext(); _LocalCreate = TRUE; //
// Now we update our visible context, which is the dfs name context
// seen by people when they do api calls.
// For the ad blob root folder, this will be the domain name of this
// machine.
//
Status = DfsGetDomainName( &_DfsVisibleContext ); } else { Status = DfsCreateUnicodeStringFromString(&_DfsVisibleContext, NameContext); } }
if (Status == ERROR_SUCCESS) { _pBlobCache = new DfsADBlobCache(&Status, GetLogicalShare(), this); if ( _pBlobCache == NULL ) { Status = ERROR_NOT_ENOUGH_MEMORY; } //
// If the constructor returns an error, the caller will release the reference
// on this BlobCache which in turn will desctruct it.
//
}
*pStatus = Status;
DFS_TRACE_LOW(REFERRAL_SERVER, "Created new root folder,%p, cache %p, name %wZ\n", this, _pBlobCache, GetLogicalShare()); }
//+-------------------------------------------------------------------------
//
// Function: Synchronize
//
// Arguments: None
//
// Returns: Status: Success or Error status code
//
// Description: This routine synchronizes the children folders
// of this root.
//
//--------------------------------------------------------------------------
DFSSTATUS DfsADBlobRootFolder::Synchronize(BOOLEAN fForceSync, BOOLEAN CalledByApi ) { DFSSTATUS Status = ERROR_SUCCESS; //
// Read from the metadata store, and unravel the blob.
// Update the ADBlobCache with the information of each individual
// link, deleting old inof, adding new info, and/or modifying
// existing information.
//
//
// if we are in a standby mode, we dont synchronize, till we obtain
// ownership again.
//
DFS_TRACE_LOW(REFERRAL_SERVER, "Synchronize started on root %p (%wZ)\n", this, GetLogicalShare());
Status = AcquireRootLock(); if (Status != ERROR_SUCCESS) { return Status; }
if (CheckRootFolderSkipSynchronize() == TRUE) { ReleaseRootLock(); return ERROR_SUCCESS; }
//
// now acquire the root share directory. If this
// fails, we continue our operation: we can continue
// with synchonize and not create directories.
// dfsdev:we need to post a eventlog or something when
// we run into this.
//
do { DFSSTATUS RootStatus = AcquireRootShareDirectory(); if(CalledByApi && (RootStatus != ERROR_SUCCESS)) { DFS_TRACE_ERROR_LOW(RootStatus, REFERRAL_SERVER, "Recognize Dfs: Root folder for %p, validate status %x\n", this, RootStatus ); Status = RootStatus; break; }
if (IsRootScalabilityMode() == TRUE) { //
// Dont have to get blob from PDC
//
Status = UpdateRootFromBlob(fForceSync, FALSE);
DFS_TRACE_LOW(REFERRAL_SERVER, "Loose Sync, Update root from blob Status %x\n", Status);
} else { //
// have to to get blob from PDC
//
Status = UpdateRootFromBlob(fForceSync, TRUE);
DFS_TRACE_LOW(REFERRAL_SERVER, "Tight Sync, Update root from blob Status %x\n", Status); }
if(CalledByApi && (Status != ERROR_SUCCESS)) {
DFS_TRACE_ERROR_LOW(Status, REFERRAL_SERVER, "Recognize Dfs: Synchronize Root folder for %p, validate status %x\n", this, Status ); (void) ReleaseRootShareDirectory(); }
} while (0);
ReleaseRootLock();
DFS_TRACE_LOW(REFERRAL_SERVER, "Synchronize done on root %p, Status %x\n", this, Status); return Status; }
DFSSTATUS DfsADBlobRootFolder::UpdateRootFromBlob( BOOLEAN fForceSync, BOOLEAN FromPDC) { DFSSTATUS Status; //
// Read in the blob from the AD, enumerate it,
// and put the data in the cache.
//
Status = GetMetadataBlobCache()->CacheRefresh( fForceSync, FromPDC ); if (Status == ERROR_SUCCESS) { Status = EnumerateBlobCacheAndCreateFolders( );
if (Status == ERROR_SUCCESS) { //
// Mark it so we know the root folder has finished
// syncing.
//
SetRootFolderSynchronized(); } else { ClearRootFolderSynchronized(); } } return Status; }
DFSSTATUS DfsADBlobRootFolder::EnumerateBlobCacheAndCreateFolders( ) { DFSSTATUS UpdateStatus;
DFSSTATUS Status = STATUS_SUCCESS; DfsADBlobCache * pBlobCache = NULL; PDFSBLOB_DATA pBlobData = NULL; DFSBOB_ITER Iter;
pBlobCache = GetMetadataBlobCache();
pBlobData = pBlobCache->FindFirstBlob(&Iter);
while (pBlobData && (!DfsIsShuttingDown())) { if (pBlobCache->IsStaleBlob(pBlobData)) { DFSSTATUS RemoveStatus;
RemoveStatus = RemoveLinkFolder( pBlobData->BlobName.Buffer ); DFS_TRACE_ERROR_LOW(RemoveStatus, REFERRAL_SERVER, "Remove stale folder %ws, status %x\n", pBlobData->BlobName.Buffer, RemoveStatus );
if (RemoveStatus == ERROR_SUCCESS) { RemoveStatus = pBlobCache->RemoveNamedBlob( &pBlobData->BlobName ); }
DFS_TRACE_ERROR_LOW(RemoveStatus, REFERRAL_SERVER, "Remove stale folder %ws, status %x\n", pBlobData->BlobName.Buffer, RemoveStatus ); } pBlobData = pBlobCache->FindNextBlob(&Iter); }
pBlobCache->FindCloseBlob(&Iter);
pBlobData = pBlobCache->FindFirstBlob(&Iter);
while (pBlobData && (!DfsIsShuttingDown())) { if (pBlobCache->IsStaleBlob(pBlobData) == FALSE) {
UpdateStatus = UpdateLinkInformation((DFS_METADATA_HANDLE) pBlobCache, pBlobData->BlobName.Buffer);
DFS_TRACE_ERROR_LOW(UpdateStatus, REFERRAL_SERVER, "Root %p (%wZ) Ad Blob enumerate, update link returned %x for %wZ\n", this, GetLogicalShare(), UpdateStatus, &pBlobData->BlobName);
if (UpdateStatus != ERROR_SUCCESS) { Status = UpdateStatus; } }
pBlobData = pBlobCache->FindNextBlob(&Iter); } pBlobCache->FindCloseBlob(&Iter);
DFS_TRACE_ERROR_LOW(Status, REFERRAL_SERVER, "Root %p (%wZ) Done with Enumerate blob and create folders, Status %x\n", this, GetLogicalShare(), Status);
return Status; }
//+-------------------------------------------------------------------------
//
// Function: RenameLinks
//
// Arguments:
// OldDomainName
// NewDomainName
//
// Returns: SUCCESS or error
//
// Description: Renames all links referencing the old domain name to the new.
//--------------------------------------------------------------------------
DFSSTATUS DfsADBlobRootFolder::RenameLinks( IN LPWSTR OldDomainName, IN LPWSTR NewDomainName) { DFSSTATUS Status = ERROR_SUCCESS; DfsADBlobCache * pBlobCache = NULL; PDFSBLOB_DATA pBlobData = NULL; DFS_METADATA_HANDLE RootHandle = NULL; PUNICODE_STRING pLinkMetadataName = NULL; UNICODE_STRING OldUnicodeName, NewUnicodeName; DFSBOB_ITER Iter; Status = AcquireRootLock(); if (Status != ERROR_SUCCESS) { return Status; }
Status = DfsRtlInitUnicodeStringEx( &OldUnicodeName, OldDomainName ); if (Status != ERROR_SUCCESS) { goto Exit; }
Status = DfsRtlInitUnicodeStringEx( &NewUnicodeName, NewDomainName ); if (Status != ERROR_SUCCESS) { goto Exit; }
pBlobCache = GetMetadataBlobCache(); RootHandle = CreateMetadataHandle(pBlobCache); //
// Iterate over all the blobs and rename its links
// if applicable. The root blob itself is in here distinguished
// by an empty LinkMetadataName (ie. \DomainRoot\"").
//
for (pBlobData = pBlobCache->FindFirstBlob(&Iter); pBlobData != NULL; pBlobData = pBlobCache->FindNextBlob(&Iter)) { if (pBlobCache->IsStaleBlob(pBlobData)) continue; pLinkMetadataName = &pBlobData->BlobName; //
// Go through all the replicas in this blob and rename
// them if need be. This will set the modified metadata back in the cache.
// We can't continue if we've hit an error at any point. This is an
// atomic rename.
//
Status = GetMetadataStore()->RenameLinks( RootHandle, pLinkMetadataName, &OldUnicodeName, &NewUnicodeName );
if (Status != ERROR_SUCCESS) break; } pBlobCache->FindCloseBlob(&Iter);
//
// Now rename the remoteServerName attribute in the AD as well.
//
if (Status == ERROR_SUCCESS) { DFSSTATUS DeleteStatus = ERROR_SUCCESS; BOOLEAN NeedToDelete = FALSE;
//
// When DfsDnsConfig flag is on, the server name with FQDN
// gets put on the remoteServerName attribute. See if the old
// name is there. This will do a GetEx on the AD object to find out.
//
DeleteStatus = DfsIsRemoteServerNameEqual( GetLogicalShare()->Buffer, &OldUnicodeName, &NeedToDelete );
// The return status isn't propagated outside. There's no need for it.
if (DeleteStatus == ERROR_SUCCESS && NeedToDelete) { UNICODE_STRING Context;
DeleteStatus = GetVisibleContext(&Context);
//
// Context here will give us the DC to contact
// for this root. The DomainName referred to here isn't necessarily a domain name.
// For this it's actually the root target name. The only reason users want to
// change the remoteServerName attribute when doing domain renames is if
// the DfsDnsConfig flag is set and that attribute has the fullyqualified servername in it.
//
if (DeleteStatus == ERROR_SUCCESS) { DeleteStatus = DfsUpdateRootRemoteServerName( GetLogicalShare()->Buffer, Context.Buffer, OldDomainName, GetRootPhysicalShareName()->Buffer, FALSE ); //
// Now, add the new one.
//
if (DeleteStatus == ERROR_SUCCESS) { Status = DfsUpdateRootRemoteServerName( GetLogicalShare()->Buffer, Context.Buffer, NewDomainName, GetRootPhysicalShareName()->Buffer, TRUE ); }
ReleaseVisibleContext(&Context); }
} } //
// Flush the cache to make our changes permanent. If there were errors
// purge our changes and refresh our cache.
//
if (Status == ERROR_SUCCESS) { Flush(); } else { ReSynchronize( TRUE ); }
if(RootHandle != NULL) { ReleaseMetadataHandle( RootHandle ); }
Exit:
ReleaseRootLock(); return Status; }
VOID DfsADBlobRootFolder::SynchronizeRoots( ) { DfsFolderReferralData *pReferralData = NULL; DFS_INFO_101 DfsState; DFSSTATUS Status, SyncStatus; DfsReplica *pReplica = NULL; ULONG Target = 0; UNICODE_STRING DfsName;
PUNICODE_STRING pRootShare; ULONG SyncCount = 0, ReplicaCount = 0; BOOLEAN CacheHit = FALSE;
if (IsRootScalabilityMode() == TRUE) { DFS_TRACE_LOW(REFERRAL_SERVER, "Loose Sync updates not sent to target servers\n"); return; }
DfsState.State = DFS_STORAGE_STATE_MASTER;
pRootShare = GetLogicalShare();
Status = GetReferralData( &pReferralData, &CacheHit);
if (Status == ERROR_SUCCESS) { ReplicaCount = pReferralData->ReplicaCount;
for (Target = 0; Target < pReferralData->ReplicaCount; Target++) { PUNICODE_STRING pTargetServer, pTargetFolder; pReplica = &pReferralData->pReplicas[ Target ]; pTargetServer = pReplica->GetTargetServer(); pTargetFolder = pRootShare; if (DfsIsTargetCurrentMachine(pTargetServer)) { continue; }
Status = DfsCreateUnicodePathString( &DfsName, 2, pTargetServer->Buffer, pTargetFolder->Buffer );
if (Status == ERROR_SUCCESS) { SyncStatus = AddRootToSyncrhonize( &DfsName );
if (SyncStatus == ERROR_SUCCESS) { SyncCount++; } DfsFreeUnicodeString( &DfsName ); }
if (DfsIsShuttingDown()) { break; } } pReferralData->ReleaseReference(); }
DFS_TRACE_LOW( REFERRAL_SERVER, "Synchronize roots %wZ done: %x roots, %x succeeded\n", pRootShare, ReplicaCount, SyncCount);
return NOTHING; }
|