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.
593 lines
18 KiB
593 lines
18 KiB
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
|
|
|