|
|
//+----------------------------------------------------------------------------
//
// Copyright (C) 2000, Microsoft Corporation
//
// File: DfsADBlobStore.cxx
//
// Contents: the AD Blob DFS Store class, this contains the registry
// specific functionality.
//
// Classes: DfsADBlobStore.
//
// History: Dec. 8 2000, Author: udayh
// April 9 2001 Rohanp - Added ADSI specific code
//
//-----------------------------------------------------------------------------
#include "DfsADBlobStore.hxx"
#include "DfsADBlobRootFolder.hxx"
#include "DfsFilterApi.hxx"
#include "dfsmisc.h"
#include "lmdfs.h"
#include "shlwapi.h"
#include "align.h"
#include "dfserror.hxx"
#include "DomainControllerSupport.hxx"
#include "dfsadsiapi.hxx"
#include "dfsinit.hxx"
#include "DfsAdBlobStore.tmh"
//+----------------------------------------------------------------------------
//
// Class: DfsADBlobStore.
//
// Synopsis: This class inherits the basic DfsStore, and extends it
// to include the blob DS specific functionality.
//
//-----------------------------------------------------------------------------
//+-------------------------------------------------------------------------
//
// Function: StoreRecognizer - the recognizer for the store.
//
// Arguments: Name - the namespace of interest.
//
// Returns: Status
// ERROR_SUCCESS on success
// ERROR status code otherwise
//
//
// Description: This routine checks if the specified namespace holds
// a domain based DFS. If it does, it reads in the
// root in that namespace and creates and adds it to our
// list of known roots, if it doesn't already exist in our list.
//
//--------------------------------------------------------------------------
DFSSTATUS DfsADBlobStore::StoreRecognizer( LPWSTR Name ) { DFSSTATUS Status = ERROR_SUCCESS; HKEY ADBlobDfsKey; BOOLEAN MachineContacted = FALSE;
DFSSTATUS NewDfsStatus = ERROR_SUCCESS; //
// Make sure the namespace is the name of a machine. FT based
// dfs exist only on domains.
//
if (IsEmptyString(Name) == FALSE) { Status = DfsIsThisADomainName( Name ); }
DFS_TRACE_LOW(REFERRAL_SERVER, "DfsADBlob:StoreRecognizer, %ws Is domain Status %x\n", Name, Status);
//
// Now, open the registry key where we store all the DFS root
// information.
//
if ( Status == ERROR_SUCCESS ) { Status = GetNewADBlobRegistryKey( Name, FALSE, // write permission not required
&MachineContacted, &ADBlobDfsKey );
if (Status == ERROR_SUCCESS) { Status = StoreRecognizeNewDfs( Name, ADBlobDfsKey );
RegCloseKey( ADBlobDfsKey ); } }
//
// Need to refine the return status further: success should mean
// machine is not domain dfs or we have read the domain dfs data
// correctly.
//
DFS_TRACE_ERROR_LOW(Status, REFERRAL_SERVER, "DfsADBlob:StoreRecognizer, Status %x\n", Status);
return Status; }
//+-------------------------------------------------------------------------
//
// Function: StoreRecognizer - the recognizer for the store.
//
// Arguments: DfsNameContext - the namespace of interest.
// LogicalShare
//
// Returns: Status
// ERROR_SUCCESS on success
// ERROR status code otherwise
//
//
// Description: This routine checks if the specified namespace holds
// a domain based DFS. If it does, it reads in the
// root in that namespace and creates and adds it to our
// list of known roots, if it doesn't already exist in our list.
//
//--------------------------------------------------------------------------
DFSSTATUS DfsADBlobStore::StoreRecognizer ( LPWSTR DfsNameContext, PUNICODE_STRING pLogicalShare ) { DFSSTATUS Status;
Status = DfsIsThisADomainName( DfsNameContext );
if (Status == ERROR_SUCCESS) { Status = StoreRecognizeNewDfs( DfsNameContext, pLogicalShare ); }
DFS_TRACE_ERROR_LOW(Status, REFERRAL_SERVER, "DfsADBlob:StoreRecognizer (remote), Status %x\n", Status); return Status; }
//+-------------------------------------------------------------------------
//
// Function: CreateNewRootFolder - creates a new root folder
//
// Arguments:
// LPWSTR DfsNameContextString - name context string
// LPWSTR RootRegKeyName - the registry holding the information about this root.
// PUNICODE_STRING pLogicalShare - the logical share name.
// PUNICODE_STRING pPhysicalShare - the physical share name.
// DfsRootFolder **ppRoot - root to return.
//
//
// Returns: Status
// ERROR_SUCCESS on success
// ERROR status code otherwise
//
//
// Description: This routine creates a new root folder, and
// adds it to the list of known roots.
//
//--------------------------------------------------------------------------
DFSSTATUS DfsADBlobStore::CreateNewRootFolder ( LPWSTR DfsNameContextString, LPWSTR RootRegKeyName, PUNICODE_STRING pLogicalShare, PUNICODE_STRING pPhysicalShare, DfsRootFolder **ppRoot ) { DFSSTATUS Status = ERROR_SUCCESS; DfsRootFolder *pNewRoot = NULL;
//
// Create a new instance of the RegistryRootFolder class.
// This gives us a reference RootFolder.
//
pNewRoot = new DfsADBlobRootFolder( DfsNameContextString, RootRegKeyName, pLogicalShare, pPhysicalShare, this, &Status ); if ( NULL == pNewRoot ) { Status = ERROR_NOT_ENOUGH_MEMORY; }
if ( ERROR_SUCCESS == Status ) { //
// AddRootFolder to the list of known roots. AddRootFolder
// is responsible to acquire any reference on the root folder
// if it is storing a reference to this root.
Status = AddRootFolder( pNewRoot, NewRootList );
if ( ERROR_SUCCESS == Status ) { //
// We were successful, return the reference root. The reference
// that we are returning is the create reference on the new root.
//
*ppRoot = pNewRoot; } else { pNewRoot->ReleaseReference(); pNewRoot = NULL; } } else { //
// Our constructor may have failed. E.g. DC may be down.
// Release our reference to this root and unwind.
//
if (pNewRoot != NULL) { pNewRoot->ReleaseReference(); pNewRoot = NULL; } }
DFS_TRACE_ERROR_LOW(Status, REFERRAL_SERVER, "ADBlobStore::CreateNewRootFolder. New root %p, for share %wZ (%wZ) on machine %ws. Status %x\n", pNewRoot, pLogicalShare, pPhysicalShare, DfsNameContextString, Status);
return Status; }
//+-------------------------------------------------------------------------
//
// Function: GetMetadataReplicaBlob - gets the replica blob
//
// Arguments: DfsMetadataHandle - the handle to the root
// MetadataName - name of the metadata
// ppBlob - the replica blob
// pBlobSize-size of blob
// pLastModifiedTime - time the blob was last modified
//
// Returns: Status
// STATUS_SUCCESS if we could read the information
// error status otherwise.
//
//
// Description: This routine read the replica blob and returns a copy
//
//--------------------------------------------------------------------------
DFSSTATUS DfsADBlobStore::GetMetadataReplicaBlob( IN DFS_METADATA_HANDLE DfsMetadataHandle, IN LPWSTR MetadataName, OUT PVOID *ppBlob, OUT PULONG pBlobSize, OUT PFILETIME pLastModifiedTime ) {
UNREFERENCED_PARAMETER(pLastModifiedTime); // dfsdev: investigate.
DFSSTATUS Status = ERROR_SUCCESS; PVOID pMetadata; ULONG MetadataSize; PVOID pUseBlob; ULONG UseBlobSize; PVOID pReplicaBlob = NULL; ULONG ReplicaBlobSize;
PDFS_NAME_INFORMATION pNameInformation = NULL;
Status = GetMetadata( (PVOID)DfsMetadataHandle, MetadataName, NULL, &pMetadata, &MetadataSize, NULL); // pass NULL For time information.
if (Status == ERROR_SUCCESS) { pNameInformation = new DFS_NAME_INFORMATION; if(pNameInformation != NULL) { RtlZeroMemory (pNameInformation, sizeof(DFS_NAME_INFORMATION)); pUseBlob = ((PDFSBLOB_DATA)(pMetadata))->pBlob; UseBlobSize = MetadataSize; Status = PackGetNameInformation( pNameInformation, &pUseBlob, &UseBlobSize );
if (Status == ERROR_SUCCESS) { PackGetULong( &ReplicaBlobSize, &pUseBlob, &UseBlobSize ); if(ReplicaBlobSize > UseBlobSize) { Status = ERROR_INVALID_DATA; } else { pReplicaBlob = (PVOID) new unsigned char [ReplicaBlobSize]; if(pReplicaBlob != NULL) { RtlCopyMemory(pReplicaBlob, pUseBlob, ReplicaBlobSize); } else { Status = ERROR_NOT_ENOUGH_MEMORY; } }
}
delete pNameInformation; } else { Status = ERROR_NOT_ENOUGH_MEMORY; } ReleaseMetadata( (PVOID)DfsMetadataHandle, pMetadata ); }
//
// If we were successful, return the read in information. Otherwise free
// up the allocate resources and return error.
//
if ( Status == STATUS_SUCCESS ) { *ppBlob = pReplicaBlob; *pBlobSize = ReplicaBlobSize; } return Status; }
//+-------------------------------------------------------------------------
//
// Function: GetMetadataNameBlob - gets the name blob
//
// Arguments: DfsMetadataHandle - the handle to the root
// MetadataName - name of the metadata
// ppBlob - the name blob
// pBlobSize-size of blob
// pLastModifiedTime - time the blob was last modified
//
// Returns: Status
// STATUS_SUCCESS if we could read the information
// error status otherwise.
//
//
// Description: This routine read the name blob and returns a copy.
//
//--------------------------------------------------------------------------
DFSSTATUS DfsADBlobStore::GetMetadataNameBlob( IN DFS_METADATA_HANDLE DfsMetadataHandle, IN LPWSTR MetadataName, OUT PVOID *ppBlob, OUT PULONG pBlobSize, OUT PFILETIME pLastModifiedTime ) {
DFSSTATUS Status = ERROR_SUCCESS; PVOID pMetadata; ULONG MetadataSize; PVOID pBlob, pUseBlob; ULONG UseBlobSize, NameBlobSize; PVOID pNameBlob = NULL;
PDFS_NAME_INFORMATION pNameInformation = NULL;
Status = GetMetadata( (PVOID)DfsMetadataHandle, MetadataName, NULL, &pMetadata, &MetadataSize, pLastModifiedTime);
if (Status == ERROR_SUCCESS) { pNameInformation = new DFS_NAME_INFORMATION; if(pNameInformation != NULL) {
RtlZeroMemory (pNameInformation, sizeof(DFS_NAME_INFORMATION)); pBlob = ((PDFSBLOB_DATA)(pMetadata))->pBlob; pUseBlob = pBlob; UseBlobSize = MetadataSize; Status = PackGetNameInformation( pNameInformation, &pUseBlob, &UseBlobSize );
if (Status == ERROR_SUCCESS) { NameBlobSize = MetadataSize - UseBlobSize; pNameBlob = (PVOID) new unsigned char [NameBlobSize ]; if(pNameBlob != NULL) { RtlCopyMemory(pNameBlob, pBlob, NameBlobSize ); } else { Status = ERROR_NOT_ENOUGH_MEMORY; } }
delete pNameInformation; } else { Status = ERROR_NOT_ENOUGH_MEMORY; } ReleaseMetadata( (PVOID)DfsMetadataHandle, pMetadata ); }
//
// If we were successful, return the read in information. Otherwise free
// up the allocate resources and return error.
//
if ( Status == STATUS_SUCCESS ) { *ppBlob = pNameBlob; *pBlobSize = NameBlobSize; } return Status; } DFSSTATUS DfsADBlobStore::SetMetadataNameBlob( DFS_METADATA_HANDLE RootHandle, LPWSTR MetadataName, PVOID pNameBlob, ULONG NameBlobSize ) { PVOID pReplicaBlob, pNewBlob; ULONG ReplicaBlobSize, NewBlobSize; FILETIME LastTime; DFSSTATUS Status;
Status = GetMetadataReplicaBlob( RootHandle, MetadataName, &pReplicaBlob, &ReplicaBlobSize, &LastTime ); if (Status == ERROR_SUCCESS) { NewBlobSize = NameBlobSize + ReplicaBlobSize; Status = AllocateMetadataBlob( &pNewBlob, NewBlobSize ); if (Status == ERROR_SUCCESS) { RtlCopyMemory(pNewBlob, pNameBlob, NameBlobSize); RtlCopyMemory((PVOID)((ULONG_PTR)pNewBlob + NameBlobSize), pReplicaBlob, ReplicaBlobSize ); Status = SetMetadata( (PVOID)RootHandle, MetadataName, NULL, pNewBlob, NewBlobSize );
ReleaseMetadataBlob( pNewBlob ); }
ReleaseMetadataReplicaBlob(pReplicaBlob, ReplicaBlobSize ); }
return Status; }
DFSSTATUS DfsADBlobStore::SetMetadataReplicaBlob( DFS_METADATA_HANDLE RootHandle, LPWSTR MetadataName, PVOID pReplicaBlob, ULONG ReplicaBlobSize ) { PVOID pNameBlob, pRemainingBlob; ULONG NameBlobSize, RemainingBlobSize; PVOID pOldBlob, pNewBlob, pUseBlob; ULONG OldBlobSize, NewBlobSize, UseBlobSize; ULONG OldReplicaBlobSize; PVOID pMetadata; ULONG MetadataSize;
DFSSTATUS Status; DFS_NAME_INFORMATION NameInformation;
Status = GetMetadata( (PVOID)RootHandle, MetadataName, NULL, &pMetadata, &MetadataSize, NULL);
if (Status == ERROR_SUCCESS) { pNameBlob = pOldBlob = ((PDFSBLOB_DATA)(pMetadata))->pBlob; OldBlobSize = MetadataSize; Status = PackGetNameInformation( &NameInformation, &pOldBlob, &OldBlobSize );
if (Status == ERROR_SUCCESS) {
Status = PackGetULong( &OldReplicaBlobSize, &pOldBlob, &OldBlobSize );
if (Status == ERROR_SUCCESS) { pRemainingBlob = (PVOID)((ULONG_PTR)pOldBlob + OldReplicaBlobSize); RemainingBlobSize = OldBlobSize - OldReplicaBlobSize; } }
if (Status == ERROR_SUCCESS) { NameBlobSize = PackSizeNameInformation( &NameInformation );
NewBlobSize = NameBlobSize + sizeof(ULONG) + ReplicaBlobSize + RemainingBlobSize; Status = AllocateMetadataBlob( &pNewBlob, NewBlobSize );
if (Status == ERROR_SUCCESS) { SYSTEMTIME CurrentTime; FILETIME ModifiedTime;
pUseBlob = pNewBlob; UseBlobSize = NewBlobSize;
GetSystemTime( &CurrentTime);
if (SystemTimeToFileTime( &CurrentTime, &ModifiedTime )) { NameInformation.LastModifiedTime = ModifiedTime; }
Status = PackSetNameInformation( &NameInformation, &pUseBlob, &UseBlobSize);
//
// At this point, we better have enough space for
// the rest of the stuff. Otherwise we have an
// internal computing problem.
//
if (Status == ERROR_SUCCESS) { if (UseBlobSize < (sizeof(ULONG) + ReplicaBlobSize + RemainingBlobSize)) { Status = ERROR_INVALID_DATA; } }
if (Status == ERROR_SUCCESS) { Status = PackSetULong( ReplicaBlobSize, &pUseBlob, &UseBlobSize ); }
if (Status == ERROR_SUCCESS) { RtlCopyMemory(pUseBlob, pReplicaBlob, ReplicaBlobSize ); pUseBlob = (PVOID)((ULONG_PTR)pUseBlob + ReplicaBlobSize); UseBlobSize -= ReplicaBlobSize;
RtlCopyMemory(pUseBlob, pRemainingBlob, RemainingBlobSize );
Status = SetMetadata( (PVOID)RootHandle, MetadataName, NULL, pNewBlob, NewBlobSize ); }
ReleaseMetadataBlob( pNewBlob ); } else { Status = ERROR_NOT_ENOUGH_MEMORY; } }
ReleaseMetadata((PVOID)RootHandle, pMetadata ); }
return Status; }
INIT_ADBLOB_DFS_ID_PROPERTY_INFO(); //+-------------------------------------------------------------------------
//
// Function: PackGetNameInformation - Unpacks the root/link name info
//
// Arguments: pDfsNameInfo - pointer to the info to fill.
// ppBuffer - pointer to buffer that holds the binary stream.
// pSizeRemaining - pointer to size of above buffer
//
// Returns: Status
// ERROR_SUCCESS if we could unpack the name info
// error status otherwise.
//
//
// Description: This routine expects the binary stream to hold all the
// information that is necessary to return a complete name
// info structure (as defined by MiADBlobDfsIdProperty). If the stream
// does not have the sufficient
// info, ERROR_INVALID_DATA is returned back.
//
//--------------------------------------------------------------------------
DFSSTATUS DfsADBlobStore::PackGetNameInformation( IN PDFS_NAME_INFORMATION pDfsNameInfo, IN OUT PVOID *ppBuffer, IN OUT PULONG pSizeRemaining) { DFSSTATUS Status = STATUS_SUCCESS;
//
// Get the name information from the binary stream.
//
Status = PackGetInformation( (ULONG_PTR)pDfsNameInfo, ppBuffer, pSizeRemaining, &MiADBlobDfsIdProperty );
if (Status == ERROR_SUCCESS) { pDfsNameInfo->LastModifiedTime = pDfsNameInfo->PrefixTimeStamp;
if ((pDfsNameInfo->Type & 0x80) == 0x80) { pDfsNameInfo->State |= DFS_VOLUME_FLAVOR_AD_BLOB; } }
return Status; }
//+-------------------------------------------------------------------------
//
// Function: PackSetNameInformation - Packs the root/link name info
//
// Arguments: pDfsNameInfo - pointer to the info to pack.
// ppBuffer - pointer to buffer that holds the binary stream.
// pSizeRemaining - pointer to size of above buffer
//
// Returns: Status
// ERROR_SUCCESS if we could pack the name info
// error status otherwise.
//
//
// Description: This routine takes the passedin name information and
// stores it in the binary stream passed in.
//
//--------------------------------------------------------------------------
DFSSTATUS DfsADBlobStore::PackSetNameInformation( IN PDFS_NAME_INFORMATION pDfsNameInfo, IN OUT PVOID *ppBuffer, IN OUT PULONG pSizeRemaining) { DFSSTATUS Status;
if ((pDfsNameInfo->Type & 0x80) == 0x80) { pDfsNameInfo->State &= ~DFS_VOLUME_FLAVORS; }
pDfsNameInfo->PrefixTimeStamp = pDfsNameInfo->LastModifiedTime; pDfsNameInfo->StateTimeStamp = pDfsNameInfo->LastModifiedTime; pDfsNameInfo->CommentTimeStamp = pDfsNameInfo->LastModifiedTime;
//
// Store the DfsNameInfo in the stream first.
//
Status = PackSetInformation( (ULONG_PTR)pDfsNameInfo, ppBuffer, pSizeRemaining, &MiADBlobDfsIdProperty );
return Status; }
//+-------------------------------------------------------------------------
//
// Function: PackSizeNameInformation - Gets the size of the name info.
//
// Arguments: pDfsNameInfo - info to size.
//
// Returns: Status
// ULONG - size needed
//
// Description: This routine gets us the size of the binary stream
// required to pack the passed in name info.
//
//--------------------------------------------------------------------------
ULONG DfsADBlobStore::PackSizeNameInformation( IN PDFS_NAME_INFORMATION pDfsNameInfo ) { ULONG Size;
Size = PackSizeInformation( (ULONG_PTR)pDfsNameInfo, &MiADBlobDfsIdProperty );
return Size; }
DFSSTATUS DfsADBlobStore::GetMetadata ( IN PVOID DfsMetadataKey, IN LPWSTR RelativeName, IN LPWSTR RegistryValueNameString, OUT PVOID *ppData, OUT ULONG *pDataSize, OUT PFILETIME pLastModifiedTime) { DFSSTATUS Status = ERROR_SUCCESS; PVOID pDataBuffer = NULL; DfsADBlobCache * pBlobCache = NULL; ULONG DataSize = 0; ULONG DataType = 0; PDFSBLOB_DATA BlobData; UNICODE_STRING BlobName;
UNREFERENCED_PARAMETER (RegistryValueNameString); UNREFERENCED_PARAMETER (pLastModifiedTime);
Status = DfsRtlInitUnicodeStringEx( &BlobName, RelativeName ); if(Status != ERROR_SUCCESS) { return Status; }
pBlobCache = (DfsADBlobCache *)ExtractFromMetadataHandle( DfsMetadataKey ); Status = pBlobCache->GetNamedBlob(&BlobName, &BlobData); if(Status == STATUS_SUCCESS) { *ppData = (PVOID) BlobData; *pDataSize = BlobData->Size; }
return Status;
}
DFSSTATUS DfsADBlobStore::SetMetadata ( IN PVOID DfsMetadataKey, IN LPWSTR RelativeName, IN LPWSTR RegistryValueNameString, IN PVOID pData, IN ULONG DataSize) {
DFSSTATUS Status = ERROR_SUCCESS; DfsADBlobCache * pBlobCache = NULL; UNICODE_STRING BlobName;
UNREFERENCED_PARAMETER (RegistryValueNameString); Status = DfsRtlInitUnicodeStringEx( &BlobName, RelativeName ); if(Status != ERROR_SUCCESS) { return Status; }
pBlobCache = (DfsADBlobCache *)ExtractFromMetadataHandle( DfsMetadataKey ); Status = pBlobCache->StoreBlobInCache(&BlobName, (PBYTE) pData, DataSize);
if (Status == ERROR_SUCCESS) { Status = pBlobCache->WriteBlobToAd(); } DFS_TRACE_LOW(REFERRAL_SERVER, "Done Setting metadata for %p %ws, Status %x\n", pBlobCache, RelativeName, Status);
return Status; }
DFSSTATUS DfsADBlobStore::RemoveMetadata ( IN PVOID DfsMetadataKey, IN LPWSTR RelativeName)
{
DFSSTATUS Status = ERROR_SUCCESS; DfsADBlobCache * pBlobCache = NULL; UNICODE_STRING BlobName;
Status = DfsRtlInitUnicodeStringEx( &BlobName, RelativeName ); if(Status != ERROR_SUCCESS) { return Status; }
pBlobCache = (DfsADBlobCache *)ExtractFromMetadataHandle( DfsMetadataKey ); Status = pBlobCache->RemoveNamedBlob( &BlobName );
if (Status == ERROR_SUCCESS) { Status = pBlobCache->WriteBlobToAd(); }
return Status; }
DFSSTATUS DfsADBlobStore::CreateADBlobRoot( LPWSTR MachineName, LPWSTR DCName, LPWSTR PhysicalShare, LPWSTR LogicalShare, LPWSTR Comment, BOOLEAN NewRoot) { DFSSTATUS Status= ERROR_SUCCESS; HKEY DfsKey = NULL; DfsRootFolder *pRootFolder = NULL; DfsRootFolder *pLookupRootFolder = NULL; BOOLEAN IsLastRootTarget = FALSE; UNICODE_STRING DfsMachine; UNICODE_STRING DfsShare; UNICODE_STRING DfsPhysicalShare;
//
// We had decided to disallow mismatch on Logical and physical
// shares, but we are just going to document this.
//
#if 0
if (_wcsicmp(LogicalShare, PhysicalShare) != 0) { return ERROR_INVALID_NAME; } #endif
DFS_TRACE_LOW( REFERRAL_SERVER, "Dfs ad blob store, create root %ws\n", LogicalShare); Status = DfsRtlInitUnicodeStringEx( &DfsShare, LogicalShare ); if(Status != ERROR_SUCCESS) { return Status; }
Status = DfsRtlInitUnicodeStringEx( &DfsPhysicalShare, PhysicalShare ); if(Status != ERROR_SUCCESS) { return Status; }
Status = DfsRtlInitUnicodeStringEx( &DfsMachine, MachineName ); if(Status != ERROR_SUCCESS) { return Status; }
if (DfsIsSpecialDomainShare(&DfsShare) || DfsIsSpecialDomainShare(&DfsPhysicalShare)) { Status = ERROR_INVALID_PARAMETER; DFS_TRACE_ERROR_LOW( Status, REFERRAL_SERVER, "Dfs ad blob store, special share - create root %ws, status %x\n", LogicalShare, Status); return Status; }
Status = LookupRoot( &DfsMachine, &DfsShare, &pLookupRootFolder );
DFS_TRACE_LOW( REFERRAL_SERVER, "Dfs ad blob store, looup root %p, status %x\n", pRootFolder, Status); if (Status == ERROR_SUCCESS) { pLookupRootFolder->ReleaseReference();
//
// DO NOT CHANGE this error code. A change here will affect the client
// The client will tear down the root if we return any other
// error code here, so be very careful.
//
// We also need to return here: the rest of the code assumes this.
//
DFS_TRACE_ERROR_LOW( Status, REFERRAL_SERVER, "Dfs ad blob store, Already Exists - create root %ws, status %x\n", LogicalShare, Status);
return ERROR_ALREADY_EXISTS; }
Status = DfsCheckServerRootHandlingCapability(); if (Status != ERROR_SUCCESS) { return Status; }
Status = GetNewADBlobRegistryKey( MachineName, TRUE, // write permission required
NULL, &DfsKey ); if (Status == ERROR_SUCCESS) { Status = SetupADBlobRootKeyInformation( DfsKey, LogicalShare, PhysicalShare );
//RegCloseKey( DfsKey );
}
if (Status == ERROR_SUCCESS) { Status = GetRootFolder( NULL, LogicalShare, &DfsShare, &DfsPhysicalShare, &pRootFolder );
if (Status == ERROR_SUCCESS) { Status = pRootFolder->RootRequestPrologue( DCName );
if (Status == ERROR_SUCCESS) { Status = AddRootToBlob( MachineName, pRootFolder, NewRoot, //NewRoot,
LogicalShare, PhysicalShare, Comment ); if ((Status == ERROR_FILE_EXISTS) || (Status == ERROR_ALREADY_EXISTS)) { Status = ERROR_SUCCESS; }
if (Status == ERROR_SUCCESS) { Status = DfsUpdateRootRemoteServerName( LogicalShare, DCName, MachineName, PhysicalShare, TRUE ); }
if (Status == ERROR_SUCCESS) { Status = pRootFolder->AcquireRootShareDirectory();
//
// now mark the root folder as synchronized:
// this is true since this root is empty.
//
if (Status == ERROR_SUCCESS) { pRootFolder->SetRootFolderSynchronized(); } } else { (void) pRootFolder->ReleaseRootShareDirectory(); }
pRootFolder->RootRequestEpilogue(); } }
}
if (Status != ERROR_SUCCESS) { DFSSTATUS LocalStatus = ERROR_SUCCESS;
LocalStatus = RegDeleteKey( DfsKey, LogicalShare );
LocalStatus = DfsUpdateRootRemoteServerName( LogicalShare, DCName, MachineName, PhysicalShare, FALSE ); if(pRootFolder) {
LocalStatus = pRootFolder->RootRequestPrologue( DCName ); if (LocalStatus == ERROR_SUCCESS) { LocalStatus = RemoveRootFromBlob( pRootFolder, MachineName, PhysicalShare, &IsLastRootTarget );
pRootFolder->RootRequestEpilogue(); }
if(IsLastRootTarget) { DfsDeleteDfsRootObject( DCName, LogicalShare); }
RemoveRootFolder(pRootFolder, TRUE); } }
if(pRootFolder) { pRootFolder->ReleaseReference(); }
if(DfsKey != NULL) { RegCloseKey( DfsKey ); }
//
// At this point we CANNOT return ERROR_ALREADY_EXISTS. The client
// will use this code to mean that the DS object it creates is not
// cleaned up.
//
// Does not mean that ERROR_NOT_SUPPORTED is a better error, but till
// we find one, this should suffice.
//
if (Status == ERROR_ALREADY_EXISTS) { Status = ERROR_NOT_SUPPORTED; }
DFS_TRACE_ERROR_LOW( Status, REFERRAL_SERVER, "Dfs ad blob store, create root %ws, status %x\n", LogicalShare, Status); return Status; }
DFSSTATUS DfsADBlobStore::DeleteADBlobRoot( LPWSTR MachineName, LPWSTR DCName, LPWSTR PhysicalShare, LPWSTR LogicalShare ) { DFSSTATUS Status = ERROR_SUCCESS; UNICODE_STRING DfsMachine; UNICODE_STRING DfsShare; DfsRootFolder *pRootFolder = NULL; BOOLEAN IsLastRootTarget = FALSE;
DFS_TRACE_LOW(REFERRAL_SERVER, "AdBlob: delete ad blob root %ws\n", LogicalShare);
Status = DfsRtlInitUnicodeStringEx( &DfsMachine, MachineName ); if (Status != ERROR_SUCCESS) { return Status; }
Status = DfsRtlInitUnicodeStringEx( &DfsShare, LogicalShare ); if (Status != ERROR_SUCCESS) { return Status; }
Status = LookupRoot( &DfsMachine, &DfsShare, &pRootFolder );
DFS_TRACE_LOW(REFERRAL_SERVER, "AdBlob: delete ad blob root %ws, Lookup root %p, Status %x\n", LogicalShare, pRootFolder, Status);
if (Status == ERROR_SUCCESS) { PUNICODE_STRING pRootPhysicalShare; UNICODE_STRING DfsPhysicalShare;
pRootPhysicalShare = pRootFolder->GetRootPhysicalShareName(); Status = DfsRtlInitUnicodeStringEx( &DfsPhysicalShare, PhysicalShare); if (Status == ERROR_SUCCESS) { if (RtlCompareUnicodeString( &DfsPhysicalShare, pRootPhysicalShare, TRUE) != 0) { Status = ERROR_INVALID_PARAMETER; } }
if (Status != ERROR_SUCCESS) { pRootFolder->ReleaseReference(); } }
if (Status == ERROR_SUCCESS) { Status = pRootFolder->RootApiRequestPrologue(TRUE, DCName);
if (Status == ERROR_SUCCESS) { Status = DoesUserHaveAccess(pRootFolder, GENERIC_ALL); if (Status == ERROR_SUCCESS) { Status = pRootFolder->AcquireRootLock(); if(Status == ERROR_SUCCESS) { pRootFolder->SetRootFolderDeleteInProgress(); pRootFolder->ReleaseRootLock(); } }
if (Status == ERROR_SUCCESS) { Status = CleanRegEntry( MachineName, LogicalShare );
if (Status == ERROR_SUCCESS) {
Status = DfsUpdateRootRemoteServerName( LogicalShare, DCName, MachineName, PhysicalShare, FALSE ); } //
// Update blob and write it back.
//
if (Status == ERROR_SUCCESS) { // dfsdev: move this function to rootfolder class.
Status = RemoveRootFromBlob( pRootFolder, MachineName, PhysicalShare, &IsLastRootTarget );
}
NTSTATUS DeleteStatus;
//
// we are done with this folder. Release the root share directory
// we had acquired earlier on: this will tell the driver we are
// no longer interested on the specified drive.
//
DeleteStatus = RemoveRootFolder( pRootFolder, TRUE ); DFS_TRACE_ERROR_HIGH( DeleteStatus, REFERRAL_SERVER, "remove root folder status %x\n", DeleteStatus);
DeleteStatus = pRootFolder->ReleaseRootShareDirectory(); DFS_TRACE_ERROR_LOW( DeleteStatus, REFERRAL_SERVER, "release root dir status %x\n", DeleteStatus); } pRootFolder->RootApiRequestEpilogue(TRUE, Status ); }
pRootFolder->ReleaseReference();
#if 0
if(Status != ERROR_SUCCESS) { DFS_TRACE_HIGH(REFERRAL_SERVER, "remove root folder failed. Trying to recreate root \n");
CreateADBlobRoot(MachineName, DCName, PhysicalShare, LogicalShare, L"", TRUE ); } #endif
}
DFS_TRACE_LOW(REFERRAL_SERVER, "AdBlob: delete ad blob root %p (%ws), Status %x\n", pRootFolder, LogicalShare, Status); return Status; }
DFSSTATUS DfsADBlobStore::DeleteADBlobRootForced( LPWSTR MachineName, LPWSTR DCName, LPWSTR PhysicalShare, LPWSTR LogicalShare ) {
DFSSTATUS Status = ERROR_SUCCESS; UNICODE_STRING DfsMachine; UNICODE_STRING DfsShare; DfsRootFolder *pRootFolder = NULL; BOOLEAN IsLastRootTarget = FALSE;
DFS_TRACE_LOW(REFERRAL_SERVER, "AdBlob: delete ad blob root %ws\n", LogicalShare);
Status = DfsRtlInitUnicodeStringEx( &DfsMachine, MachineName ); if (Status != ERROR_SUCCESS) { return Status; }
Status = DfsRtlInitUnicodeStringEx( &DfsShare, LogicalShare ); if (Status != ERROR_SUCCESS) { return Status; }
Status = GetCompatRootFolder( &DfsShare, &pRootFolder ); DFS_TRACE_LOW(REFERRAL_SERVER, "AdBlob: forced delete ad blob root %ws, Lookup root %p, Status %x\n", LogicalShare, pRootFolder, Status);
if (Status == ERROR_SUCCESS) {
Status = pRootFolder->RootApiRequestPrologue(TRUE, DCName);
if (Status == ERROR_SUCCESS) { Status = DoesUserHaveAccess(pRootFolder, GENERIC_ALL);
if (Status == ERROR_SUCCESS) { Status = pRootFolder->AcquireRootLock(); if(Status == ERROR_SUCCESS) { pRootFolder->SetRootFolderDeleteInProgress(); pRootFolder->ReleaseRootLock(); } } if (Status == ERROR_SUCCESS) { Status = DfsUpdateRootRemoteServerName( LogicalShare, DCName, MachineName, PhysicalShare, FALSE );
if (Status == ERROR_SUCCESS) { Status = RemoveRootFromBlob( pRootFolder, MachineName, PhysicalShare, &IsLastRootTarget );
} } pRootFolder->RootApiRequestEpilogue(TRUE, Status ); }
pRootFolder->ReleaseReference(); }
return Status; }
DFSSTATUS DfsADBlobStore::RemoveChild( DFS_METADATA_HANDLE DfsHandle, LPWSTR ChildName ) {
return RemoveMetadata( (PVOID)DfsHandle, ChildName ); }
//+-------------------------------------------------------------------------
//
// Function: AddChild - Add a child to the metadata.
//
// Arguments:
// DfsMetadataHandle - the Metadata key for the root.
// PUNICODE_STRING pLinkLogicalName - the logical name of the child
// LPWSTR ReplicaServer - the first target server for this link.
// LPWSTR ReplicaPath - the target path for this link
// LPWSTR Comment - the comment to be associated with this link.
// LPWSTR pMetadataName - the metadata name for the child, returned..
//
//
// Returns: Status:
//
// Description: This routine adds a child to the Root metadata. It packs
// the link name into the name information. If the replica
// information exists, it packs that into the replica info.
// It then saves the name and replica streams under the
// Childkey.
// NOTE: this function does not require that the link
// have atleast one replica. Any such requirements
// should be enforced by the caller.
//
//--------------------------------------------------------------------------
DFSSTATUS DfsADBlobStore::AddChild( IN DFS_METADATA_HANDLE DfsHandle, IN PDFS_NAME_INFORMATION pNameInfo, IN PDFS_REPLICA_LIST_INFORMATION pReplicaListInfo, IN PUNICODE_STRING pMetadataName) { DFSSTATUS Status; PVOID pNameBlob, pReplicaBlob, pNewBlob, pUseBlob; ULONG NameBlobSize, ReplicaBlobSize, NewBlobSize, UseBlobSize;
Status = CreateNameInformationBlob( pNameInfo, &pNameBlob, &NameBlobSize );
if (Status == ERROR_SUCCESS) { Status = CreateReplicaListInformationBlob( pReplicaListInfo, &pReplicaBlob, &ReplicaBlobSize );
if (Status == ERROR_SUCCESS) { NewBlobSize = NameBlobSize + sizeof(ULONG) + ReplicaBlobSize + 3 * sizeof(ULONG);
Status = AllocateMetadataBlob( &pNewBlob, NewBlobSize ); if (Status == ERROR_SUCCESS) { pUseBlob = pNewBlob; UseBlobSize = NewBlobSize;
RtlCopyMemory( pUseBlob, pNameBlob, NameBlobSize ); pUseBlob = (PVOID)((ULONG_PTR)pUseBlob + NameBlobSize); UseBlobSize -= NameBlobSize;
PackSetULong( ReplicaBlobSize, &pUseBlob, &UseBlobSize ); RtlCopyMemory(pUseBlob, pReplicaBlob, ReplicaBlobSize ); pUseBlob = (PVOID)((ULONG_PTR)pUseBlob + ReplicaBlobSize); UseBlobSize -= ReplicaBlobSize;
PackSetULong( 4, &pUseBlob, &UseBlobSize ); PackSetULong( 0, &pUseBlob, &UseBlobSize ); PackSetULong( pNameInfo->Timeout, &pUseBlob, &UseBlobSize );
Status = SetMetadata( (PVOID)DfsHandle, pMetadataName->Buffer, NULL, pNewBlob, NewBlobSize );
ReleaseMetadataBlob( pNewBlob ); }
ReleaseMetadataReplicaBlob( pReplicaBlob, ReplicaBlobSize ); } ReleaseMetadataNameBlob( pNameBlob, NameBlobSize ); }
return Status; }
DFSSTATUS DfsADBlobStore::EnumerateApiLinks( IN DFS_METADATA_HANDLE DfsHandle, PUNICODE_STRING pRootName, DWORD Level, LPBYTE pBuffer, LONG BufferSize, LPDWORD pEntriesToRead, LPDWORD pResumeHandle, PLONG pSizeRequired ) { DFSSTATUS Status = ERROR_SUCCESS; BOOLEAN OverFlow = FALSE; LONG HeaderSize = 0; LONG EntriesRead = 0; LONG EntriesToRead = *pEntriesToRead; LONG SizeRequired = 0; LONG EntryCount = 0; ULONG ChildNum = 0; LPBYTE pLinkBuffer = NULL; LONG LinkBufferSize = 0;
LPBYTE CurrentBuffer = NULL; LPBYTE NewBuffer = NULL; LONG SizeRemaining = 0;
DfsADBlobCache * pBlobCache = NULL; PDFSBLOB_DATA pBlobData = NULL; LONG CurrentCount = 0; ULONG_PTR SizeDiff; DFSBOB_ITER Iter;
pBlobCache = (DfsADBlobCache *)ExtractFromMetadataHandle( DfsHandle );
OverFlow = FALSE; Status = DfsApiSizeLevelHeader( Level, &HeaderSize ); if (Status != ERROR_SUCCESS) { return Status; }
SizeRequired = ROUND_UP_COUNT(EntriesToRead * HeaderSize, ALIGN_QUAD);
if (EntriesToRead * HeaderSize < BufferSize ) { CurrentBuffer = (LPBYTE)((ULONG_PTR)pBuffer + EntriesToRead * HeaderSize); SizeRemaining = BufferSize - EntriesToRead * HeaderSize; } else { CurrentBuffer = pBuffer; SizeRemaining = 0; OverFlow = TRUE; }
if(pResumeHandle) { EntryCount = *pResumeHandle; }
CurrentCount = 0;
pBlobData = pBlobCache->FindFirstBlob(&Iter); while ((pBlobData != NULL) && CurrentCount < EntryCount ) { CurrentCount++; pBlobData = pBlobCache->FindNextBlob(&Iter); }
while ((pBlobData != NULL) && (pBlobCache->IsStaleBlob(pBlobData))) { pBlobData = pBlobCache->FindNextBlob(&Iter); }
if (pBlobData == NULL) { Status = ERROR_NO_MORE_ITEMS; } while ((pBlobData != NULL) && (Status == ERROR_SUCCESS)) { //
// For each child, get the child name.
//
if (EntriesToRead && EntriesRead >= EntriesToRead) { break; }
Status = GetStoreApiInformationBuffer( DfsHandle, pRootName, pBlobData->BlobName.Buffer, Level, &pLinkBuffer, &LinkBufferSize );
if (Status == ERROR_SUCCESS) { SizeRequired += ROUND_UP_COUNT(LinkBufferSize, ALIGN_QUAD); if (OverFlow == FALSE) { DFSSTATUS PackStatus; PackStatus = PackageEnumerationInfo( Level, EntriesRead, pLinkBuffer, pBuffer, &CurrentBuffer, &SizeRemaining ); if (PackStatus == ERROR_BUFFER_OVERFLOW) { OverFlow = TRUE; } NewBuffer = (LPBYTE)ROUND_UP_POINTER( CurrentBuffer, ALIGN_LPVOID); SizeDiff = (NewBuffer - CurrentBuffer); if ((LONG)SizeDiff > SizeRemaining) { SizeRemaining = 0; } else { SizeRemaining -= (LONG)SizeDiff; } CurrentBuffer = NewBuffer; }
ReleaseStoreApiInformationBuffer( pLinkBuffer ); EntryCount++; EntriesRead++; } pBlobData = pBlobCache->FindNextBlob(&Iter); while ((pBlobData != NULL) && (pBlobCache->IsStaleBlob(pBlobData))) { pBlobData = pBlobCache->FindNextBlob(&Iter); } if (pBlobData == NULL) { Status = ERROR_NO_MORE_ITEMS; } }
pBlobCache->FindCloseBlob(&Iter);
*pSizeRequired = SizeRequired;
if (Status == ERROR_NO_MORE_ITEMS) { if (EntriesRead) { if (OverFlow) { Status = ERROR_BUFFER_OVERFLOW; } else { Status = ERROR_SUCCESS; } }
} else if (OverFlow) { Status = ERROR_BUFFER_OVERFLOW; } if (Status == ERROR_SUCCESS) { if(pResumeHandle) { *pResumeHandle = EntryCount; } *pEntriesToRead = EntriesRead; }
return Status; }
DFSSTATUS DfsADBlobStore::AddRootToBlob( LPWSTR MachineName, DfsRootFolder *pRootFolder, BOOLEAN NewRoot, LPWSTR LogicalShare, LPWSTR ShareName, LPWSTR Comment ) { DFS_METADATA_HANDLE RootHandle; DFSSTATUS Status;
UNICODE_STRING DomainName; UNICODE_STRING LogicalName, RootMetadataName;
DFS_NAME_INFORMATION NameInfo; DFS_REPLICA_LIST_INFORMATION ReplicaListInfo; DFS_REPLICA_INFORMATION ReplicaInfo; UUID NewUid; LPWSTR RootMetadataNameString = NULL;
Status = DfsRtlInitUnicodeStringEx( &RootMetadataName, RootMetadataNameString); if (Status != ERROR_SUCCESS) { return Status; }
Status = UuidCreate(&NewUid); if (Status != ERROR_SUCCESS) { return Status; }
Status = pRootFolder->GetMetadataHandle( &RootHandle );
if (Status == ERROR_SUCCESS) { if (NewRoot == FALSE) { Status = pRootFolder->Synchronize(FALSE, TRUE); if (Status == ERROR_SUCCESS) { Status = RootEntryExists((PVOID)RootHandle, &NewRoot); } } if (Status == ERROR_SUCCESS) { if (NewRoot) { Status = DfsGetDomainName(&DomainName); if (Status == ERROR_SUCCESS) { Status = DfsCreateUnicodePathString( &LogicalName, 1, // 1 leading path seperator.
DomainName.Buffer, LogicalShare); if (Status == ERROR_SUCCESS) { StoreInitializeNameInformation( &NameInfo, &LogicalName, &NewUid, Comment );
NameInfo.Type |= PKT_ENTRY_TYPE_REFERRAL_SVC;
StoreInitializeReplicaInformation( &ReplicaListInfo, &ReplicaInfo, MachineName, ShareName );
Status = AddChild( RootHandle, &NameInfo, &ReplicaListInfo, &RootMetadataName ); DfsFreeUnicodeString( &LogicalName); } DfsFreeUnicodeString( &DomainName ); } } else { Status = AddChildReplica( RootHandle, RootMetadataNameString, MachineName, ShareName ); } } pRootFolder->ReleaseMetadataHandle( RootHandle ); }
return Status; }
DFSSTATUS DfsADBlobStore::RemoveRootFromBlob( DfsRootFolder *pRootFolder, LPWSTR MachineName, LPWSTR ShareName, PBOOLEAN pLastRoot ) { DFS_METADATA_HANDLE RootHandle; DFSSTATUS Status = ERROR_SUCCESS; BOOLEAN LastRoot = FALSE; DfsADBlobCache *pBlobCache = NULL; LPWSTR RootMetadataNameString = NULL;
Status = pRootFolder->GetMetadataHandle( &RootHandle ); if (Status == ERROR_SUCCESS) { Status = RemoveChildReplica( RootHandle, RootMetadataNameString, MachineName, ShareName, &LastRoot, TRUE);
if((Status == ERROR_SUCCESS) || (Status == ERROR_LAST_ADMIN)) { if (LastRoot) { pBlobCache = (DfsADBlobCache *)ExtractFromMetadataHandle( RootHandle); pBlobCache->InvalidateCache(); pBlobCache->WriteBlobToAd();
}
Status = ERROR_SUCCESS;
} pRootFolder->ReleaseMetadataHandle( RootHandle ); }
if (Status == ERROR_SUCCESS) { *pLastRoot = LastRoot; }
return Status; }
DFSSTATUS DfsADBlobStore::GetMetadataNameInformation( IN DFS_METADATA_HANDLE RootHandle, IN LPWSTR MetadataName, OUT PDFS_NAME_INFORMATION *ppInfo ) { PVOID pBlob, pUseBlob; ULONG UseBlobSize, ReplicaBlobSize, RecoveryBlobSize; FILETIME BlobModifiedTime; PVOID pMetadata; ULONG MetadataSize; PDFS_NAME_INFORMATION pNewInfo = NULL; DFSSTATUS Status;
Status = GetMetadata( (PVOID)RootHandle, MetadataName, NULL, &pMetadata, &MetadataSize, &BlobModifiedTime);
if (Status == ERROR_SUCCESS) {
pBlob = ((PDFSBLOB_DATA)(pMetadata))->pBlob;
pNewInfo = new DFS_NAME_INFORMATION; if (pNewInfo != NULL) { RtlZeroMemory (pNewInfo, sizeof(DFS_NAME_INFORMATION));
pUseBlob = pBlob; UseBlobSize = MetadataSize;
Status = PackGetNameInformation( pNewInfo, &pUseBlob, &UseBlobSize );
if (Status == ERROR_SUCCESS) { Status = PackGetULong( &ReplicaBlobSize, &pUseBlob, &UseBlobSize );
if (Status == ERROR_SUCCESS) {
if(ReplicaBlobSize > UseBlobSize) { Status = ERROR_INVALID_DATA; } else { pUseBlob = (PVOID)((ULONG_PTR)pUseBlob + ReplicaBlobSize); UseBlobSize -= ReplicaBlobSize; } } } if (Status == ERROR_SUCCESS) { Status = PackGetULong( &RecoveryBlobSize, &pUseBlob, &UseBlobSize ); if (Status == ERROR_SUCCESS) {
if(RecoveryBlobSize > UseBlobSize) { Status = ERROR_INVALID_DATA; } else { pUseBlob = (PVOID)((ULONG_PTR)pUseBlob + RecoveryBlobSize); UseBlobSize -= RecoveryBlobSize; } } }
if (Status == ERROR_SUCCESS) { Status = PackGetULong( &pNewInfo->Timeout, &pUseBlob, &UseBlobSize ); }
if (Status != ERROR_SUCCESS) { ReleaseMetadata( (PVOID)RootHandle, pMetadata ); delete pNewInfo; } } else { Status = ERROR_NOT_ENOUGH_MEMORY; } }
if (Status == ERROR_SUCCESS) { pNewInfo->pData = pMetadata; pNewInfo->DataSize = MetadataSize; *ppInfo = pNewInfo; }
return Status; } VOID DfsADBlobStore::ReleaseMetadataNameInformation( IN DFS_METADATA_HANDLE RootHandle, IN PDFS_NAME_INFORMATION pNameInfo ) { ReleaseMetadata( (PVOID)RootHandle, pNameInfo->pData ); delete [] pNameInfo; }
DFSSTATUS DfsADBlobStore::SetMetadataNameInformation( IN DFS_METADATA_HANDLE RootHandle, IN LPWSTR MetadataName, IN PDFS_NAME_INFORMATION pNameInfo ) { PVOID pBlob, pUseBlob, pNewBlob; ULONG UseBlobSize, NewBlobSize; ULONG ReplicaBlobSize, RecoveryBlobSize; DFSSTATUS Status; PVOID pNameBlob; ULONG NameBlobSize; FILETIME BlobModifiedTime; PVOID pMetadata; ULONG MetadataSize;
SYSTEMTIME CurrentTime; FILETIME ModifiedTime;
GetSystemTime( &CurrentTime);
if (SystemTimeToFileTime( &CurrentTime, &ModifiedTime )) { pNameInfo->LastModifiedTime = ModifiedTime; }
Status = CreateNameInformationBlob( pNameInfo, &pNameBlob, &NameBlobSize );
if (Status == ERROR_SUCCESS) { Status = GetMetadata( (PVOID)RootHandle, MetadataName, NULL, &pMetadata, &MetadataSize, &BlobModifiedTime); } if (Status == ERROR_SUCCESS) { DFS_NAME_INFORMATION NameInformation; pBlob = ((PDFSBLOB_DATA)(pMetadata))->pBlob; pUseBlob = pBlob; UseBlobSize = MetadataSize; Status = PackGetNameInformation( &NameInformation, &pUseBlob, &UseBlobSize ); if (Status == ERROR_SUCCESS) { NewBlobSize = NameBlobSize + UseBlobSize; Status = AllocateMetadataBlob( &pNewBlob, NewBlobSize ); if (Status == ERROR_SUCCESS) { RtlCopyMemory(pNewBlob, pNameBlob, NameBlobSize); RtlCopyMemory((PVOID)((ULONG_PTR)pNewBlob + NameBlobSize), pUseBlob, UseBlobSize );
pUseBlob = (PVOID)((ULONG_PTR)pNewBlob + NameBlobSize);
if (Status == ERROR_SUCCESS) { Status = PackGetULong( &ReplicaBlobSize, &pUseBlob, &UseBlobSize ); if (Status == ERROR_SUCCESS) { pUseBlob = (PVOID)((ULONG_PTR)pUseBlob + ReplicaBlobSize); UseBlobSize -= ReplicaBlobSize; } }
if (Status == ERROR_SUCCESS) { Status = PackGetULong( &RecoveryBlobSize, &pUseBlob, &UseBlobSize ); if (Status == ERROR_SUCCESS) { pUseBlob = (PVOID)((ULONG_PTR)pUseBlob + RecoveryBlobSize); UseBlobSize -= RecoveryBlobSize; } } if (Status == ERROR_SUCCESS) { Status = PackSetULong( pNameInfo->Timeout, &pUseBlob, &UseBlobSize ); }
if (Status == ERROR_SUCCESS) { Status = SetMetadata( (PVOID)RootHandle, MetadataName, NULL, pNewBlob, NewBlobSize ); } ReleaseMetadataBlob( pNewBlob ); } } ReleaseMetadata( (PVOID)RootHandle, pMetadata ); }
return Status; }
//+-------------------------------------------------------------------------
//
// Function: RenameLinks
//
// Arguments:
// RootHandle - handle to root's metadata
// OldDomainName
// NewDomainName
//
// Returns: SUCCESS or error
//
// Description: Renames all links referencing the old domain name to the new.
// To do that, this retrieves NameInformation as well as ReplicaInformation
// from the blob cache. Once done, the metadata are written back to the
// cache. Flushing the metadata to the AD or aborting the changes is
// the caller's responsibility.
//--------------------------------------------------------------------------
DFSSTATUS DfsADBlobStore::RenameLinks( DFS_METADATA_HANDLE RootHandle, IN PUNICODE_STRING pLinkMetadataName, IN PUNICODE_STRING pOldDomainName, IN PUNICODE_STRING pNewDomainName) { DFSSTATUS Status; //
// Change the NameInfo structure first.
//
Status = RenameNameInfo( RootHandle, pLinkMetadataName, pNewDomainName, pOldDomainName );
//
// We've successfully renamed the prefix in the NameInfo. Now see if there are
// any links to change in the Replica List.
//
if (Status == ERROR_SUCCESS) { Status = RenameReplicaInfo( RootHandle, pLinkMetadataName, pNewDomainName, pOldDomainName); } return Status; }
//
// RenameNameInfoPrefix - replace both the Prefix and the ShortPrefix.
// SUCCESS indicates a successful rename.
//
//
DFSSTATUS DfsADBlobStore::RenameNameInfo( IN DFS_METADATA_HANDLE RootHandle, IN PUNICODE_STRING pLinkMetadataName, IN PUNICODE_STRING pNewDomainName, IN PUNICODE_STRING pOldDomainName) { DFSSTATUS Status; PDFS_NAME_INFORMATION pNameInfo; UNICODE_STRING FirstComponent; Status = GetMetadataNameInformation( RootHandle, pLinkMetadataName->Buffer, &pNameInfo); if (Status != ERROR_SUCCESS) { return Status; } //
// Sanity check the Prefix string of the NameInfo.
// Although the LinkMetadataName is NULL for
// the root the NameInfo->Prefix has the real name.
//
Status = DfsGetFirstComponent( &pNameInfo->Prefix, &FirstComponent, NULL );
if ((Status != ERROR_SUCCESS) || (RtlEqualDomainName(pOldDomainName, &FirstComponent) == FALSE)) { ReleaseMetadataNameInformation( RootHandle, pNameInfo ); return Status; } //
// We have a match. Just replace that first component with the
// new domain name. The substitution happens in place, so we ideally should save
// the old pointer to patch back the nameinfo snapshot afterwards.
//
Status = GenerateMetadataLogicalName(pNewDomainName, &pNameInfo->Prefix, &pNameInfo->Prefix); if (Status == ERROR_SUCCESS) { //
// Similarly, change the ShortPrefix as well. We don't just assume
// that they are identical, although in practice they are currently.
//
Status = GenerateMetadataLogicalName(pNewDomainName, &pNameInfo->ShortPrefix, &pNameInfo->ShortPrefix);
// We don't bother to modify the timestamps.
//
// We don't bother to undo our previous changes if we get errors.
// The understanding is that the whole metadata blob will be
// thrown away without getting written back to the AD. Just free the old
// NameInfo strings on our way out.
//
if (Status == ERROR_SUCCESS) { Status = SetMetadataNameInformation( RootHandle, pLinkMetadataName->Buffer, pNameInfo ); ReleaseMetadataLogicalName( &pNameInfo->ShortPrefix ); } ReleaseMetadataLogicalName( &pNameInfo->Prefix ); }
//
// Release our snapshot of the blob. This doesn't write the changes back to the cache;
// the SetMetadata above does that.
//
ReleaseMetadataNameInformation( RootHandle, pNameInfo ); return Status; }
//
// RenameReplicaInfo - Walk through the replica list and replace stale domain names.
//
DFSSTATUS DfsADBlobStore::RenameReplicaInfo( IN DFS_METADATA_HANDLE RootHandle, IN PUNICODE_STRING pLinkMetadataName, IN PUNICODE_STRING pNewDomainName, IN PUNICODE_STRING pOldDomainName) { DFSSTATUS Status; PUNICODE_STRING pReplicaName; PDFS_REPLICA_LIST_INFORMATION pReplicaList; BOOLEAN RenamedLink = FALSE; ULONG i;
//
// Get a snapshot of the replica set.
//
Status = GetMetadataReplicaInformation( RootHandle, pLinkMetadataName->Buffer, &pReplicaList ); if (Status != ERROR_SUCCESS) { return Status; }
//
// Go through all its links looking for a match of the stale domain name.
//
for (i = 0; i < pReplicaList->ReplicaCount; i++) { pReplicaName = &pReplicaList->pReplicas[i].ServerName; //
// The names must match to change the replica.
//
if (!RtlEqualDomainName( pOldDomainName, pReplicaName )) { continue; } // XXX: Ideally we should keep a pointer to the old ServerName
// and put it back after we SetMetadata and before we release
// this NameInfo snapshot. The current logic basically assumes that losing
// the old pointer doesn't end in a memory leak (TRUE currently).
//
Status = DfsRtlInitUnicodeStringEx( pReplicaName, pNewDomainName->Buffer ); if (Status != ERROR_SUCCESS) { // The rootfolder will resynchronize to revert the changes.
break; } RenamedLink = TRUE; }
if ((Status == ERROR_SUCCESS) && (RenamedLink)) { //
// Put the blob back in the cache if we've changed any of it.
// We don't need to make this operation atomic with respect to
// NameInfo changes because if any of these fails, the caller's supposed to
// purge the cache with a ReSynchronize().
//
Status = SetMetadataReplicaInformation( RootHandle, pLinkMetadataName->Buffer, pReplicaList ); } ReleaseMetadataReplicaInformation( RootHandle, pReplicaList ); return Status; }
//
// This removes the target share from the
// Microsoft\Dfs\Roots\Domain registry key.
//
DFSSTATUS DfsADBlobStore::CleanRegEntry( LPWSTR MachineName, LPWSTR LogicalShare ) { HKEY FtDfsKey; DFSSTATUS Status; DFSSTATUS RetStatus = ERROR_NOT_FOUND; Status = GetNewADBlobRegistryKey( MachineName, TRUE, // write permission required
NULL, &FtDfsKey );
if (Status == ERROR_SUCCESS) { Status = RegDeleteKey( FtDfsKey, LogicalShare );
// Return success only if something got successfully deleted.
if (Status == ERROR_SUCCESS) { RetStatus = Status; } RegCloseKey( FtDfsKey ); }
return RetStatus; }
DFSSTATUS DfsADBlobStore::GenerateApiLogicalPath ( IN PUNICODE_STRING pRootName, IN PUNICODE_STRING pMetadataPrefix, IN PUNICODE_STRING pApiLogicalName ) {
DFSSTATUS Status; UNICODE_STRING FirstComponent; UNICODE_STRING Remaining; //
// For the ad blob store, the metadata prefix holds the
// name context, the share name and the link name.
// However, we will want to replace the first component
// with the rootname, so that when domains are renamed,
// we keep passing back correct information even though
// the blob has not been updated.
//
if (DfsCheckSubstitutePaths()) { Status = DfsGetFirstComponent( pMetadataPrefix, &FirstComponent, &Remaining ); if (Status == ERROR_SUCCESS) { Status = DfsCreateUnicodePathStringFromUnicode( pApiLogicalName, 2, // 2 leading path sep
pRootName, &Remaining ); } } else { //
// The caller has disabled path name substitution because she wants to see
// things as is. So just make a copy.
//
Status = DfsCreateUnicodePathStringFromUnicode(pApiLogicalName, 2, // 2 leading path separators
pMetadataPrefix, NULL); }
return Status; }
DFSSTATUS DfsADBlobStore::GetCompatRootFolder( PUNICODE_STRING pName, DfsRootFolder **ppNewRoot ) { DfsADBlobRootFolder *pNewRoot = NULL; UNICODE_STRING DomainName; DFSSTATUS Status = ERROR_SUCCESS;
*ppNewRoot = NULL; Status = DfsGetDomainName( &DomainName ); if (Status != ERROR_SUCCESS) { return Status; }
pNewRoot = new DfsADBlobRootFolder( DomainName.Buffer, L"Unknown", pName, pName, this, &Status ); //
// The root folder made a copy of this, so we are safe to delete.
//
DfsReleaseDomainName( &DomainName ); // The new operator may fail.
if (pNewRoot == NULL) { Status = ERROR_NOT_ENOUGH_MEMORY; return Status; }
if (Status == ERROR_SUCCESS) { pNewRoot->ResetCreateDirectories();
//set this so we read from this DC, instead of the PDC.
pNewRoot->SetRootScalabilityMode();
Status = pNewRoot->Synchronize( TRUE );
if (Status == ERROR_SUCCESS) { *ppNewRoot = pNewRoot; } }
if (Status != ERROR_SUCCESS) { ASSERT(pNewRoot); pNewRoot->ReleaseReference(); }
return Status; }
DFSSTATUS DfsADBlobStore::DoesUserHaveAccess(DfsRootFolder *pRootFolder, DWORD DesiredAccess) { DFS_METADATA_HANDLE RootHandle = NULL; DFSSTATUS Status = ERROR_SUCCESS; DfsADBlobCache *pBlobCache = NULL;
Status = pRootFolder->GetMetadataHandle( &RootHandle ); if (Status == ERROR_SUCCESS) { pBlobCache = (DfsADBlobCache *)ExtractFromMetadataHandle( RootHandle);
Status = pBlobCache->DfsDoesUserHaveAccess(DesiredAccess);
pRootFolder->ReleaseMetadataHandle( RootHandle ); }
return Status; }
|