2020-09-30 16:53:49 +02:00

1743 lines
53 KiB
C++

//+----------------------------------------------------------------------------
//
// 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 "DelegationControl.hxx"
#include "dfsadsiapi.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: 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;
//
// 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.
if ( ERROR_SUCCESS == Status)
{
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();
}
}
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);
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 );
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); // dfsdev: investigate
if (Status == ERROR_SUCCESS)
{
pNameBlob = pOldBlob = ((PDFSBLOB_DATA)(pMetadata))->pBlob;
OldBlobSize = MetadataSize;
Status = PackGetNameInformation( &NameInformation,
&pOldBlob,
&OldBlobSize );
if (Status == ERROR_SUCCESS)
{
NameBlobSize = MetadataSize - OldBlobSize;
Status = PackGetULong( &OldReplicaBlobSize,
&pOldBlob,
&OldBlobSize );
if (Status == ERROR_SUCCESS)
{
pRemainingBlob = (PVOID)((ULONG_PTR)pOldBlob + OldReplicaBlobSize);
RemainingBlobSize = OldBlobSize - OldReplicaBlobSize;
}
}
if (Status == ERROR_SUCCESS)
{
NewBlobSize = NameBlobSize + sizeof(ULONG) + ReplicaBlobSize + RemainingBlobSize;
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;
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)
{
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;
}
//
// 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);
RtlInitUnicodeString( &BlobName, RelativeName );
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;
BOOLEAN ImpersonationDisabled = FALSE;
UNREFERENCED_PARAMETER (RegistryValueNameString);
//
// check for return status and do something?
//
DfsDisableRpcImpersonation(&ImpersonationDisabled);
RtlInitUnicodeString( &BlobName, RelativeName );
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);
if (ImpersonationDisabled)
{
DfsReEnableRpcImpersonation();
}
return Status;
}
DFSSTATUS
DfsADBlobStore::RemoveMetadata (
IN PVOID DfsMetadataKey,
IN LPWSTR RelativeName)
{
DFSSTATUS Status = ERROR_SUCCESS;
DfsADBlobCache * pBlobCache = NULL;
UNICODE_STRING BlobName;
BOOLEAN ImpersonationDisabled = FALSE;
DfsDisableRpcImpersonation(&ImpersonationDisabled);
RtlInitUnicodeString( &BlobName, RelativeName );
pBlobCache = (DfsADBlobCache *)ExtractFromMetadataHandle( DfsMetadataKey );
Status = pBlobCache->RemoveNamedBlob( &BlobName );
if (Status == ERROR_SUCCESS)
{
Status = pBlobCache->WriteBlobToAd();
}
if (ImpersonationDisabled)
{
DfsReEnableRpcImpersonation();
}
return Status;
}
DFSSTATUS
DfsADBlobStore::CreateADBlobRoot(
LPWSTR MachineName,
LPWSTR DCName,
LPWSTR PhysicalShare,
LPWSTR LogicalShare,
LPWSTR Comment,
BOOLEAN NewRoot,
PDFSM_ROOT_LIST *ppRootList )
{
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;
BOOLEAN ImpersonationDisabled = FALSE;
UNREFERENCED_PARAMETER (ppRootList); //dfsdev investigate.
//
// dfsdev: disallow differing logical/physical share names.
// check for proper error returns.
//
#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);
RtlInitUnicodeString( &DfsShare, LogicalShare );
RtlInitUnicodeString( &DfsPhysicalShare, PhysicalShare );
RtlInitUnicodeString( &DfsMachine, MachineName );
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.
//
return ERROR_ALREADY_EXISTS;
}
Status = GetNewADBlobRegistryKey( MachineName,
TRUE, // write permission required
NULL,
&DfsKey );
if (Status == ERROR_SUCCESS)
{
Status = SetupADBlobRootKeyInformation( DfsKey,
LogicalShare,
PhysicalShare );
//RegCloseKey( DfsKey );
}
DfsDisableRpcImpersonation(&ImpersonationDisabled);
if (Status == ERROR_SUCCESS)
{
Status = GetRootFolder( NULL,
LogicalShare,
&DfsShare,
&DfsPhysicalShare,
&pRootFolder );
if (Status == ERROR_SUCCESS)
{
Status = AddRootToBlob( 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();
if (Status != ERROR_SUCCESS)
{
//
// make a best effort to remove ourselves
// dont care about status return, thoug
// we may want to log it.
//dfsdev: add logging.
//
//RemoveRootFolder(pRootFolder,
//TRUE); // permanent removal
}
//
// now mark the root folder as synchronized:
// this is true since this root is empty.
//
if (Status == ERROR_SUCCESS)
{
pRootFolder->SetRootFolderSynchronized();
}
}
//pRootFolder->ReleaseReference();
}
DFSLOG("Add AD Blob Root, adding root folder status %x\n", Status);
}
if (Status != ERROR_SUCCESS)
{
DFSSTATUS LocalStatus = ERROR_SUCCESS;
//
// dfsdev: undo all the blob stuff, and finally remove our registry
// entry
LocalStatus = RegDeleteKey( DfsKey,
LogicalShare );
LocalStatus = DfsUpdateRootRemoteServerName( LogicalShare,
DCName,
MachineName,
PhysicalShare,
FALSE );
if(pRootFolder)
{
LocalStatus = RemoveRootFromBlob( pRootFolder,
MachineName,
PhysicalShare,
&IsLastRootTarget );
if(IsLastRootTarget)
{
DfsDeleteDfsRootObject( DCName,
LogicalShare);
}
RemoveRootFolder(pRootFolder, TRUE);
}
}
if(pRootFolder)
{
pRootFolder->ReleaseReference();
}
if(DfsKey != NULL)
{
RegCloseKey( DfsKey );
}
if (ImpersonationDisabled)
{
DfsReEnableRpcImpersonation();
}
//
// 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,
PDFSM_ROOT_LIST *ppRootList )
{
UNREFERENCED_PARAMETER(ppRootList); //dfsdev: investigate.
DFSSTATUS Status;
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);
RtlInitUnicodeString( &DfsMachine, MachineName );
RtlInitUnicodeString( &DfsShare, LogicalShare );
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)
{
Status = pRootFolder->AcquireRootLock();
if (Status == ERROR_SUCCESS)
{
pRootFolder->SetRootFolderDeleteInProgress();
pRootFolder->ReleaseRootLock();
}
}
if (Status == ERROR_SUCCESS)
{
Status = pRootFolder->RootApiRequestPrologue(TRUE);
if (Status == ERROR_SUCCESS)
{
HKEY FtDfsKey;
Status = GetNewADBlobRegistryKey( MachineName,
TRUE, // write permission required
NULL,
&FtDfsKey );
if (Status == ERROR_SUCCESS)
{
Status = RegDeleteKey( FtDfsKey,
LogicalShare );
RegCloseKey( FtDfsKey );
}
}
if (Status == ERROR_SUCCESS)
{
BOOLEAN ImpersonationDisabled = FALSE;
DfsDisableRpcImpersonation(&ImpersonationDisabled);
Status = DfsUpdateRootRemoteServerName( LogicalShare,
DCName,
MachineName,
PhysicalShare,
FALSE );
//
// Update blob and write it back.
//
if (Status == ERROR_SUCCESS)
{
Status = RemoveRootFromBlob( pRootFolder,
MachineName,
PhysicalShare,
&IsLastRootTarget );
if (Status == ERROR_SUCCESS)
{
#if 0
if (IsLastRootTarget == TRUE)
{
DFSSTATUS DeleteObjectStatus;
DeleteObjectStatus = DfsDeleteDfsRootObject( DCName,
LogicalShare);
DFS_TRACE_ERROR_LOW(DeleteObjectStatus, REFERRAL_SERVER,
"Object %ws deleted from AD: status %x\n",
LogicalShare, DeleteObjectStatus);
}
#endif
}
}
pRootFolder->RootApiRequestEpilogue(TRUE,
Status );
if (ImpersonationDisabled)
{
DfsReEnableRpcImpersonation();
}
}
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->ReleaseReference();
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,
ppRootList );
}
}
DFS_TRACE_LOW(REFERRAL_SERVER, "AdBlob: delete ad blob root %p (%ws), Status %x\n",
pRootFolder, LogicalShare, Status);
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;
LONG HeaderSize;
LONG EntriesRead = 0;
LONG EntriesToRead = *pEntriesToRead;
LONG SizeRequired = 0;
LONG EntryCount = 0;
ULONG ChildNum = 0;
LPBYTE pLinkBuffer = NULL;
LONG LinkBufferSize = 0;
LPBYTE CurrentBuffer, NewBuffer;
LONG SizeRemaining;
ULONG_PTR SizeDiff;
DfsADBlobCache * pBlobCache = NULL;
PDFSBLOB_DATA pBlobData = NULL;
DFSBOB_ITER Iter;
LONG CurrentCount;
pBlobCache = (DfsADBlobCache *)ExtractFromMetadataHandle( DfsHandle );
OverFlow = FALSE;
HeaderSize = DfsApiSizeLevelHeader( Level );
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;
}
EntryCount = *pResumeHandle;
CurrentCount = 0;
pBlobData = pBlobCache->FindFirstBlob(&Iter);
while ((pBlobData != NULL) &&
CurrentCount < EntryCount )
{
CurrentCount++;
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);
if (pBlobData == NULL)
{
Status = ERROR_NO_MORE_ITEMS;
}
} while (Status == ERROR_SUCCESS);
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)
{
*pResumeHandle = EntryCount;
*pEntriesToRead = EntriesRead;
}
return Status;
}
DFSSTATUS
DfsADBlobStore::AddRootToBlob(
DfsRootFolder *pRootFolder,
BOOLEAN NewRoot,
LPWSTR LogicalShare,
LPWSTR ShareName,
LPWSTR Comment )
{
DFS_METADATA_HANDLE RootHandle;
DFSSTATUS Status;
UNICODE_STRING MachineName, DomainName;
UNICODE_STRING LogicalName, RootMetadataName;
DFS_NAME_INFORMATION NameInfo;
DFS_REPLICA_LIST_INFORMATION ReplicaListInfo;
DFS_REPLICA_INFORMATION ReplicaInfo;
UUID NewUid;
LPWSTR RootMetadataNameString = NULL;
RtlInitUnicodeString( &RootMetadataName, RootMetadataNameString);
Status = UuidCreate(&NewUid);
if (Status != ERROR_SUCCESS)
{
return Status;
}
Status = DfsGetMachineName(&MachineName);
if (Status != ERROR_SUCCESS)
{
return Status;
}
Status = pRootFolder->GetMetadataHandle( &RootHandle );
if (Status == ERROR_SUCCESS)
{
if (NewRoot == FALSE)
{
pRootFolder->Synchronize();
if ( RootEntryExists((PVOID)RootHandle) != ERROR_SUCCESS )
{
NewRoot = TRUE;
}
}
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 |= 0x80; // dfsdev: hack. mark it for root correctly.
StoreInitializeReplicaInformation( &ReplicaListInfo,
&ReplicaInfo,
MachineName.Buffer,
ShareName );
Status = AddChild( RootHandle,
&NameInfo,
&ReplicaListInfo,
&RootMetadataName );
DfsFreeUnicodeString( &LogicalName);
}
DfsFreeUnicodeString( &DomainName );
}
}
else
{
Status = pRootFolder->Synchronize();
if (Status == ERROR_SUCCESS)
{
Status = AddChildReplica( RootHandle,
RootMetadataNameString,
MachineName.Buffer,
ShareName );
}
}
pRootFolder->ReleaseMetadataHandle( RootHandle );
}
DfsFreeUnicodeString(&MachineName );
return Status;
}
DFSSTATUS
DfsADBlobStore::RemoveRootFromBlob(
DfsRootFolder *pRootFolder,
LPWSTR MachineName,
LPWSTR ShareName,
PBOOLEAN pLastRoot )
{
DFS_METADATA_HANDLE RootHandle;
DFSSTATUS Status;
BOOLEAN LastRoot = FALSE;
DfsADBlobCache *pBlobCache;
LPWSTR RootMetadataNameString = NULL;
Status = pRootFolder->GetMetadataHandle( &RootHandle );
if (Status == ERROR_SUCCESS)
{
Status = RemoveChildReplica( RootHandle,
RootMetadataNameString,
MachineName,
ShareName,
&LastRoot );
if (Status == ERROR_SUCCESS)
{
pBlobCache = (DfsADBlobCache *)ExtractFromMetadataHandle( RootHandle);
pBlobCache->InvalidateCache();
if (LastRoot)
{
pBlobCache->WriteBlobToAd();
}
}
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)
{
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 = 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;
Status = CreateNameInformationBlob( pNameInfo,
&pNameBlob,
&NameBlobSize );
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;
}