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.
2008 lines
63 KiB
2008 lines
63 KiB
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Copyright (C) 2000, Microsoft Corporation
|
|
//
|
|
// File: DfsRegistryStore.cxx
|
|
//
|
|
// Contents: the Registry DFS Store class, this contains the registry
|
|
// specific functionality.
|
|
//
|
|
// Classes: DfsRegistryStore.
|
|
//
|
|
// History: Dec. 8 2000, Author: udayh
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
#include "DfsRegistryStore.hxx"
|
|
#include "DfsRegistryRootFolder.hxx"
|
|
#include "DfsFilterApi.hxx"
|
|
#include "dfsmisc.h"
|
|
|
|
#include "domainControllerSupport.hxx"
|
|
#include "DfsRegStrings.hxx"
|
|
#include "shlwapi.h"
|
|
#include "align.h"
|
|
|
|
//
|
|
// logging specific includes
|
|
//
|
|
#include "DfsRegistryStore.tmh"
|
|
|
|
extern
|
|
DFSSTATUS
|
|
MigrateDfs(
|
|
LPWSTR MachineName);
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Class: DfsRegistryStore
|
|
//
|
|
// Synopsis: This class inherits the basic DfsStore, and extends it
|
|
// to include the registry specific functionality.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
LPWSTR DfsRegistryNameString = L"ID";
|
|
LPWSTR DfsRegistryRecoveryString = L"Recovery";
|
|
LPWSTR DfsRegistryReplicaString = L"Svc";
|
|
LPWSTR DfsRegistryDfsDriverLocation = DFS_REG_DFS_DRIVER_LOCATION;
|
|
LPWSTR DfsLocalVolumesValue = DFS_REG_LOCAL_VOLUMES_CHILD;
|
|
extern LPWSTR DfsVolumesLocation;
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// 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 registry 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
|
|
DfsRegistryStore::StoreRecognizer(
|
|
LPWSTR Name )
|
|
{
|
|
DFSSTATUS Status = ERROR_SUCCESS;
|
|
HKEY OldStandaloneDfsKey = NULL;
|
|
HKEY StandaloneDfsKey = NULL;
|
|
BOOLEAN MachineContacted = FALSE;
|
|
|
|
//
|
|
// Make sure the namespace is the name of a machine. Registry based
|
|
// dfs exist only on machines.
|
|
//
|
|
|
|
if (IsEmptyString(Name) == FALSE)
|
|
{
|
|
Status = DfsIsThisAMachineName( Name );
|
|
if(Status != ERROR_SUCCESS)
|
|
{
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
|
|
DFS_TRACE_LOW(REFERRAL_SERVER, "DfsRegistryStore:StoreRecognizer, Name %ws Is Machine Status %x\n", Name, Status);
|
|
|
|
|
|
//
|
|
// we now find all the migrated multiple roots standalone DFS's as
|
|
// well as the old single root standalone DFS, and add them to our
|
|
// in memory metadata.
|
|
//
|
|
Status = GetNewStandaloneRegistryKey( Name,
|
|
FALSE,
|
|
&MachineContacted,
|
|
&StandaloneDfsKey );
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = StoreRecognizeNewDfs( Name,
|
|
StandaloneDfsKey );
|
|
|
|
RegCloseKey( StandaloneDfsKey );
|
|
}
|
|
|
|
//
|
|
// Need to refine the return status further: success should mean
|
|
// machine is not std dfs or we have read the std dfs data correctly.
|
|
//
|
|
DFS_TRACE_ERROR_LOW( Status, REFERRAL_SERVER, "Dfs registry store recognizser, 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
|
|
DfsRegistryStore::StoreRecognizer (
|
|
LPWSTR DfsNameContext,
|
|
PUNICODE_STRING pLogicalShare )
|
|
{
|
|
DFSSTATUS Status;
|
|
|
|
Status = DfsIsThisAMachineName( DfsNameContext );
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = StoreRecognizeNewDfs( DfsNameContext,
|
|
pLogicalShare );
|
|
}
|
|
|
|
DFS_TRACE_ERROR_LOW(Status, REFERRAL_SERVER, "DfsRegistryStore:StoreRecognizer (remote), Status %x\n",
|
|
Status);
|
|
return Status;
|
|
}
|
|
|
|
|
|
DFSSTATUS
|
|
DfsRegistryStore::LookupDotNetRootByName(
|
|
LPWSTR ShareName,
|
|
DfsRootFolder **ppRootFolder )
|
|
{
|
|
|
|
DFSSTATUS Status = ERROR_SUCCESS;
|
|
HKEY DfsKey = NULL;
|
|
HKEY DfsRootKey = NULL;
|
|
|
|
Status = GetNewStandaloneRegistryKey( NULL,
|
|
FALSE,
|
|
NULL,
|
|
&DfsKey );
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = RegOpenKeyEx( DfsKey,
|
|
ShareName,
|
|
0,
|
|
KEY_READ,
|
|
&DfsRootKey );
|
|
|
|
RegCloseKey(DfsKey );
|
|
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = GetRootFolder( NULL,
|
|
ShareName,
|
|
DfsRootKey,
|
|
ppRootFolder );
|
|
RegCloseKey(DfsRootKey);
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
DFSSTATUS
|
|
DfsRegistryStore::LookupOldRootByName(
|
|
LPWSTR ShareName,
|
|
DfsRootFolder **ppRootFolder )
|
|
{
|
|
|
|
DFSSTATUS Status = ERROR_SUCCESS;
|
|
HKEY DfsKey = NULL;
|
|
HKEY DfsRootKey = NULL;
|
|
UNICODE_STRING LogicalShare;
|
|
|
|
Status = GetOldStandaloneRegistryKey( NULL,
|
|
FALSE,
|
|
NULL,
|
|
&DfsRootKey );
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = GetRootPhysicalShare( DfsRootKey,
|
|
&LogicalShare);
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
if (_wcsicmp(ShareName, LogicalShare.Buffer) != 0)
|
|
{
|
|
Status = ERROR_NOT_FOUND;
|
|
|
|
ReleaseRootLogicalShare( &LogicalShare );
|
|
}
|
|
}
|
|
|
|
|
|
if(Status == ERROR_SUCCESS)
|
|
{
|
|
Status = MigrateDfs( L"" );
|
|
if(Status == ERROR_SUCCESS)
|
|
{
|
|
|
|
Status = GetRootFolder( L"",
|
|
ShareName,
|
|
&LogicalShare,
|
|
&LogicalShare,
|
|
ppRootFolder );
|
|
}
|
|
|
|
|
|
ReleaseRootLogicalShare( &LogicalShare );
|
|
}
|
|
|
|
|
|
if(DfsRootKey != NULL)
|
|
{
|
|
RegCloseKey( DfsRootKey );
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
DFSSTATUS
|
|
DfsRegistryStore::LookupNewRootByName(
|
|
LPWSTR ShareName,
|
|
DfsRootFolder **ppRootFolder )
|
|
{
|
|
DFSSTATUS Status = ERROR_NOT_FOUND;
|
|
|
|
if(DfsIsMachineCluster())
|
|
{
|
|
Status = LookupOldRootByName (ShareName, ppRootFolder);
|
|
if(Status != ERROR_SUCCESS)
|
|
{
|
|
Status = LookupDotNetRootByName (ShareName, ppRootFolder);
|
|
}
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
#if 0
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: StoreRecognizeOldStandaloneDfs - recognizer for single root dfs
|
|
//
|
|
// Arguments: Name - the namespace of interest.
|
|
// HKEY OldDfsKey.
|
|
//
|
|
// Returns: Status
|
|
// ERROR_SUCCESS on success
|
|
// ERROR status code otherwise
|
|
//
|
|
//
|
|
// Description: This routine reads a single root from the old standalone
|
|
// location, and loads it in if the root exists.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
DFSSTATUS
|
|
DfsRegistryStore::StoreRecognizeOldStandaloneDfs(
|
|
LPWSTR MachineName,
|
|
HKEY OldDfsKey )
|
|
{
|
|
DfsRootFolder *pRootFolder = NULL;
|
|
DFSSTATUS Status = ERROR_SUCCESS;
|
|
DFSSTATUS RootStatus = ERROR_SUCCESS;
|
|
UNICODE_STRING LogicalRoot;
|
|
UNICODE_STRING DfsNameContext;
|
|
UNREFERENCED_PARAMETER(MachineName);
|
|
|
|
RtlZeroMemory(&LogicalRoot, sizeof(LogicalRoot));
|
|
|
|
//
|
|
// Check if we have a root folder read from the old dfs location
|
|
// ("domainroot"). If we have not seen the root already, and one
|
|
// exists, a new root folder gets created.
|
|
// Status = DfsGetRegValueString (OldDfsKey,
|
|
// DfsRootShareValueName,
|
|
// &LogicalRoot);
|
|
|
|
Status = GetRootPhysicalShare(OldDfsKey,&LogicalRoot);
|
|
if(Status == ERROR_SUCCESS)
|
|
{
|
|
|
|
|
|
RtlInitUnicodeStringEx( &DfsNameContext, NULL);
|
|
|
|
//
|
|
// Check if we already know about this root. If we do, this
|
|
// routine gives us a referenced root folder which we can return.
|
|
// If not, we create a brand new root folder.
|
|
//
|
|
|
|
Status = LookupRoot( &DfsNameContext,
|
|
&LogicalRoot,
|
|
&pRootFolder );
|
|
|
|
//
|
|
// we did not find a root, so create a new one.
|
|
//
|
|
if ( Status != ERROR_SUCCESS )
|
|
{
|
|
Status = MigrateStdDfs( L"",
|
|
OldDfsKey,
|
|
(LPWSTR) LogicalRoot.Buffer,
|
|
(LPWSTR) LogicalRoot.Buffer,
|
|
FALSE);
|
|
if(Status == ERROR_SUCCESS)
|
|
{
|
|
|
|
//
|
|
// Now get either an existing root by this name,
|
|
// or create a new one.
|
|
//
|
|
RootStatus = GetRootFolder( L"",
|
|
LogicalRoot.Buffer,
|
|
&LogicalRoot,
|
|
&LogicalRoot,
|
|
&pRootFolder );
|
|
|
|
if (RootStatus == ERROR_SUCCESS)
|
|
{
|
|
|
|
//
|
|
// Call the synchronize method on the root to
|
|
// update it with the latest children.
|
|
// Again, ignore the error since we need to move
|
|
// on to the next root.
|
|
// dfsdev: need eventlog to signal this.
|
|
//
|
|
RootStatus = pRootFolder->Synchronize();
|
|
|
|
//
|
|
// If the Synchronize above had succeeded, then it would
|
|
// all the reparse points that the root needs. Now we n
|
|
// this volume as one that has DFS reparse points so th
|
|
// to perform garbage collection on this volume later o
|
|
//
|
|
(VOID)pRootFolder->AddReparseVolumeToList();
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
ReleaseRootPhysicalShare( &LogicalRoot );
|
|
}
|
|
|
|
|
|
if(pRootFolder != NULL)
|
|
{
|
|
pRootFolder->ReleaseReference();
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
#endif
|
|
#if 0
|
|
DFSSTATUS
|
|
DfsRegistryStore::StoreRecognizeOldStandaloneDfs(
|
|
LPWSTR MachineName,
|
|
HKEY OldDfsKey )
|
|
{
|
|
DfsRootFolder *pRootFolder = NULL;
|
|
DFSSTATUS Status = ERROR_SUCCESS;
|
|
|
|
//
|
|
// Check if we have a root folder read from the old dfs location
|
|
// ("domainroot"). If we have not seen the root already, and one
|
|
// exists, a new root folder gets created.
|
|
//
|
|
Status = GetRootFolder( MachineName,
|
|
NULL,
|
|
OldDfsKey,
|
|
&pRootFolder );
|
|
|
|
//
|
|
// We got a root folder. call synchronize on it to update its contents.
|
|
// The synchronize method fills the root with the most upto date
|
|
// children data.
|
|
//
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
|
|
DFSSTATUS RootStatus;
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
RootStatus = pRootFolder->AcquireRootShareDirectory();
|
|
|
|
//
|
|
// Call the synchronize method on the root to
|
|
// update it with the latest children.
|
|
// Again, ignore the error since we need to move
|
|
// on to the next root.
|
|
// dfsdev: need eventlog to signal this.
|
|
//
|
|
RootStatus = pRootFolder->Synchronize();
|
|
|
|
DFSLOG("Root folder for %ws, Synchronize status %x\n",
|
|
RootStatus );
|
|
|
|
// Release our reference on the root folder.
|
|
|
|
pRootFolder->ReleaseReference();
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: CreateNewRootFolder - creates a new root folder
|
|
//
|
|
// Arguments: Name - the namespace of interest.
|
|
// pPrefix - the logical share for this DFs.
|
|
// ppRoot - the newly created root.
|
|
//
|
|
//
|
|
// Returns: Status
|
|
// ERROR_SUCCESS on success
|
|
// ERROR status code otherwise
|
|
//
|
|
//
|
|
// Description: This routine creates a new registry root folder, and
|
|
// adds it to the list of known roots.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
DFSSTATUS
|
|
DfsRegistryStore::CreateNewRootFolder (
|
|
LPWSTR MachineName,
|
|
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 DfsRegistryRootFolder( MachineName,
|
|
RootRegKeyName,
|
|
pLogicalShare,
|
|
pPhysicalShare,
|
|
this,
|
|
&Status );
|
|
|
|
if ( pNewRoot == NULL )
|
|
{
|
|
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
|
|
{
|
|
if(pNewRoot != NULL)
|
|
{
|
|
pNewRoot->ReleaseReference();
|
|
pNewRoot = NULL;
|
|
}
|
|
}
|
|
|
|
DFS_TRACE_ERROR_LOW(Status, REFERRAL_SERVER, "RegistryStore::CreateNewRootFolder. New root %p, for root %wZ (%wZ) on machine %ws. Status %x\n",
|
|
*ppRoot, pLogicalShare, pPhysicalShare, MachineName, Status);
|
|
|
|
return Status;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: GetMetadata- Gets the DFS metadata information
|
|
//
|
|
// Arguments: DfsMetadataKey - The key under which the information exists
|
|
// RelativeName - the name of the subkey, having info of interest
|
|
// RegistryValueNameString - The value name that holds the info.
|
|
// ppData - the pointer that holds data buffer being returned
|
|
// pDataSize - pointer to size of data being returned.
|
|
//
|
|
// Returns: Status
|
|
// STATUS_SUCCESS if we could read the information,
|
|
// error status otherwise.
|
|
//
|
|
//
|
|
// Description: This routine reads the value of interest under the specified
|
|
// key/subkey. The information is read in a buffer allocated
|
|
// by this routine, and the buffer is returned to the caller.
|
|
// It is the caller's responsibility to free this buffer when
|
|
// done.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
DFSSTATUS
|
|
DfsRegistryStore::GetMetadata (
|
|
IN HKEY DfsMetadataKey,
|
|
IN LPWSTR RelativeName,
|
|
IN LPWSTR RegistryValueNameString,
|
|
OUT PVOID *ppData,
|
|
OUT ULONG *pDataSize,
|
|
OUT PFILETIME pLastModifiedTime)
|
|
{
|
|
|
|
HKEY NewKey = NULL;
|
|
HKEY UseKey = NULL;
|
|
PVOID pDataBuffer = NULL;
|
|
ULONG DataSize, DataType;
|
|
DFSSTATUS Status = ERROR_SUCCESS;
|
|
|
|
//
|
|
// If a relative name was passed in, we need to open a subkey under the
|
|
// passed in key. Otherwise, we already have a key open to the information
|
|
// of interest.
|
|
//
|
|
if ( RelativeName != NULL )
|
|
{
|
|
Status = RegOpenKeyEx( DfsMetadataKey,
|
|
RelativeName,
|
|
0,
|
|
KEY_READ,
|
|
&NewKey );
|
|
if ( Status == ERROR_SUCCESS )
|
|
{
|
|
UseKey = NewKey;
|
|
}
|
|
else
|
|
{
|
|
DFS_TRACE_HIGH( REFERRAL_SERVER, "registry store, GetMetadata-RegOpenKeyEx %ws status=%d\n", RelativeName, Status);
|
|
}
|
|
} else
|
|
{
|
|
UseKey = DfsMetadataKey;
|
|
}
|
|
|
|
//
|
|
// Get the largest size of any value under the key of interest, so we know
|
|
// how much we need to allocate in the worst case.
|
|
// (If a subkey has 3 values, this returns the maximum memory size required
|
|
// to read any one of the values.)
|
|
//
|
|
if ( Status == ERROR_SUCCESS )
|
|
{
|
|
Status = RegQueryInfoKey( UseKey, // Key
|
|
NULL, // Class string
|
|
NULL, // Size of class string
|
|
NULL, // Reserved
|
|
NULL, // # of subkeys
|
|
NULL, // max size of subkey name
|
|
NULL, // max size of class name
|
|
NULL, // # of values
|
|
NULL, // max size of value name
|
|
&DataSize, // max size of value data,
|
|
NULL, // security descriptor
|
|
pLastModifiedTime ); // Last write time
|
|
}
|
|
|
|
//
|
|
// We have the required size now: allocate a buffer for that size and
|
|
// read the value we are interested in.
|
|
//
|
|
if ( Status == ERROR_SUCCESS )
|
|
{
|
|
pDataBuffer = new BYTE [DataSize];
|
|
|
|
if ( pDataBuffer == NULL )
|
|
{
|
|
Status = ERROR_NOT_ENOUGH_MEMORY;
|
|
} else
|
|
{
|
|
Status = RegQueryValueEx( UseKey,
|
|
RegistryValueNameString,
|
|
NULL,
|
|
&DataType,
|
|
(LPBYTE)pDataBuffer,
|
|
&DataSize );
|
|
//
|
|
// If the format of data is not a certain type (usually binary type for DFS)
|
|
// we have bogus data.
|
|
//
|
|
if ( (Status == ERROR_SUCCESS) && (DataType != DFS_REGISTRY_DATA_TYPE) )
|
|
{
|
|
Status = ERROR_INVALID_DATA;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we are successful in reading the value, pass the allcoated buffer and
|
|
// size back to caller. Otherwise, free up the allocate buffer and return
|
|
// error status to the caller.
|
|
//
|
|
if ( Status == ERROR_SUCCESS )
|
|
{
|
|
*ppData = pDataBuffer;
|
|
*pDataSize = DataSize;
|
|
}
|
|
else
|
|
{
|
|
if ( pDataBuffer != NULL )
|
|
{
|
|
delete [] pDataBuffer;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we did open a new key, it is time to close it now.
|
|
//
|
|
if ( NewKey != NULL )
|
|
RegCloseKey(NewKey);
|
|
|
|
DFS_TRACE_LOW( REFERRAL_SERVER, "registry store, GetMetadata-leaving %ws status=%d\n", RelativeName, Status);
|
|
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: SetMetadata- Sets the DFS metadata information
|
|
//
|
|
// Arguments: DfsMetadataKey - The key under which the information exists
|
|
// RelativeName - the name of the subkey, to store info
|
|
// RegistryValueNameString - The value name that holds the info.
|
|
// pData - the pointer that holds data buffer
|
|
// DataSize - Size of data
|
|
//
|
|
// Returns: Status
|
|
// STATUS_SUCCESS if we could write the information,
|
|
// error status otherwise.
|
|
//
|
|
//
|
|
// Description: This routine writes the value of interest under the specified
|
|
// key/subkey.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
DFSSTATUS
|
|
DfsRegistryStore::SetMetadata (
|
|
IN HKEY DfsMetadataKey,
|
|
IN LPWSTR RelativeName,
|
|
IN LPWSTR RegistryValueNameString,
|
|
IN PVOID pData,
|
|
IN ULONG DataSize )
|
|
{
|
|
|
|
HKEY UseKey = NULL;
|
|
DFSSTATUS Status = ERROR_SUCCESS;
|
|
|
|
//
|
|
// If a relative name was passed in, we need to open a subkey under the
|
|
// passed in key. Otherwise, we already have a key open to the information
|
|
// of interest.
|
|
//
|
|
Status = RegOpenKeyEx( DfsMetadataKey,
|
|
RelativeName,
|
|
0,
|
|
KEY_READ | KEY_WRITE,
|
|
&UseKey );
|
|
|
|
//
|
|
// Store the value against the passed in value string
|
|
//
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = RegSetValueEx( UseKey,
|
|
RegistryValueNameString,
|
|
NULL,
|
|
DFS_REGISTRY_DATA_TYPE,
|
|
(LPBYTE)pData,
|
|
DataSize );
|
|
RegCloseKey(UseKey);
|
|
}
|
|
|
|
DFS_TRACE_LOW( REFERRAL_SERVER, "registry store, SetMetadata-RegOpenKeyEx %ws status=%d\n", RelativeName, Status);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: GetRootKey - get the root key
|
|
//
|
|
// Arguments: Name - the namespace of interest.
|
|
// pMachineContacted - did we contact the machine?
|
|
// pDfsRootKey - the returned key.
|
|
//
|
|
// Returns: Status
|
|
// ERROR_SUCCESS on success
|
|
// ERROR status code otherwise
|
|
//
|
|
//
|
|
// Description: This routine connects to the appropriate machine, and
|
|
// opens the DFS metadata information in the registry.
|
|
// If it succeeds, the machine hosts a registry DFs, and
|
|
// the opened key is returned.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
DFSSTATUS
|
|
DfsRegistryStore::GetRootKey(
|
|
LPWSTR MachineName,
|
|
LPWSTR ChildName,
|
|
BOOLEAN *pMachineContacted,
|
|
OUT PHKEY pDfsRootKey )
|
|
{
|
|
DFSSTATUS Status;
|
|
HKEY DfsStdRegistryKey;
|
|
LPWSTR UseChildName = NULL;
|
|
|
|
if (IsEmptyString(ChildName) == FALSE)
|
|
{
|
|
UseChildName = ChildName;
|
|
}
|
|
|
|
//
|
|
// If there is no childname specified, we are dealing with the
|
|
// old style dfs: a single root exists on the machine under "domainroot".
|
|
// so open that key, and return it.
|
|
// If a childname is specified, we are dealing with a migrated
|
|
// dfs. Open the specified child in the new location.
|
|
//
|
|
|
|
if (UseChildName != NULL)
|
|
{
|
|
Status = GetNewStandaloneRegistryKey( MachineName,
|
|
FALSE,
|
|
pMachineContacted,
|
|
&DfsStdRegistryKey );
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// We then open the required child key, and close
|
|
// the parents key.
|
|
//
|
|
Status = RegOpenKeyEx( DfsStdRegistryKey,
|
|
ChildName,
|
|
0,
|
|
KEY_READ,
|
|
pDfsRootKey );
|
|
|
|
RegCloseKey( DfsStdRegistryKey );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// no name was specified. This must be the old standalone
|
|
// child. (single root)
|
|
//
|
|
Status = GetOldStandaloneRegistryKey( MachineName,
|
|
FALSE,
|
|
pMachineContacted,
|
|
pDfsRootKey );
|
|
}
|
|
|
|
DFSLOG("DfsRegistryStore::GetDfsRootKey %ws Machine, Contacted %d Status %x\n",
|
|
MachineName, pMachineContacted ? *pMachineContacted : 2, Status );
|
|
|
|
return Status;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: GetDataRecoveryInformation - Gets recovery info
|
|
//
|
|
// Arguments: DfsMetadataKey - an open key to the registry.
|
|
// RelativeName - Name of a subkey under the above key.
|
|
// pRecoveryState - The recovery state we read.
|
|
//
|
|
// Returns: Status
|
|
// STATUS_SUCCESS if we could read the information
|
|
// error status otherwise.
|
|
//
|
|
//
|
|
// Description: This routine read the RECOVERY value for the Root or link of
|
|
// a dfs tree and returns with the value.
|
|
// A non-zero state means that some recovery is required.
|
|
// Note that there is more information in the RECOVERY value than
|
|
// the state. Currently, we ignore that information and just return
|
|
// the state.
|
|
// In the future, we dont plan to use this value.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
DFSSTATUS
|
|
DfsRegistryStore::GetDataRecoveryState (
|
|
IN HKEY DfsMetadataKey,
|
|
IN LPWSTR RelativeName,
|
|
OUT PULONG pRecoveryState )
|
|
{
|
|
DFSSTATUS Status = ERROR_SUCCESS;
|
|
PVOID DataBuffer = NULL, CurrentBuffer;
|
|
ULONG DataSize, CurrentSize;
|
|
|
|
Status = GetMetadata (DfsMetadataKey,
|
|
RelativeName,
|
|
DfsRegistryRecoveryString,
|
|
&DataBuffer,
|
|
&DataSize,
|
|
NULL ); // we dont care about last mod time.
|
|
|
|
//
|
|
// We are currently interested in the first word in the data stream.
|
|
// This holds the recovery state.
|
|
//
|
|
|
|
if ( Status == STATUS_SUCCESS )
|
|
{
|
|
CurrentBuffer = DataBuffer;
|
|
CurrentSize = DataSize;
|
|
Status = PackGetULong( pRecoveryState,
|
|
&CurrentBuffer,
|
|
&CurrentSize );
|
|
}
|
|
|
|
ReleaseMetadataBlob( DataBuffer );
|
|
|
|
//
|
|
// If we could not read the value, then we return success and
|
|
// and indicate state of 0. This is so that we can support roots
|
|
// or links that dont have this value.
|
|
//
|
|
if ( Status != ERROR_SUCCESS )
|
|
{
|
|
DFSLOG("DfsRegistryStore::DfsGetDataRecoveryState Status %x\n",
|
|
Status);
|
|
|
|
*pRecoveryState = 0;
|
|
Status = ERROR_SUCCESS;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
INIT_STANDALONE_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 MiDfsIdProperty). If the stream
|
|
// does not have the sufficient
|
|
// info, ERROR_INVALID_DATA is returned back.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
DFSSTATUS
|
|
DfsRegistryStore::PackGetNameInformation(
|
|
IN PDFS_NAME_INFORMATION pDfsNameInfo,
|
|
IN OUT PVOID *ppBuffer,
|
|
IN OUT PULONG pSizeRemaining)
|
|
{
|
|
DFSSTATUS Status;
|
|
|
|
//
|
|
// Get the name information from the binary stream.
|
|
//
|
|
Status = PackGetInformation( (ULONG_PTR)pDfsNameInfo,
|
|
ppBuffer,
|
|
pSizeRemaining,
|
|
&MiStdDfsIdProperty );
|
|
//
|
|
// Immediately following the name value is a timeout value.
|
|
// This is not in the MiDfsIdProperty because it appers that some
|
|
// of the older DFS may not have the timeout value.
|
|
//
|
|
if ( Status == ERROR_SUCCESS )
|
|
{
|
|
pDfsNameInfo->LastModifiedTime = pDfsNameInfo->PrefixTimeStamp;
|
|
|
|
Status = PackGetULong(&pDfsNameInfo->Timeout,
|
|
ppBuffer,
|
|
pSizeRemaining);
|
|
//
|
|
// Use a default value if we cannot get the timeout value in
|
|
// the stream.
|
|
//
|
|
if ( Status != ERROR_SUCCESS )
|
|
{
|
|
pDfsNameInfo->Timeout = 300; // hard code this value.
|
|
Status = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
if ((pDfsNameInfo->Type & 0x80) == 0x80)
|
|
{
|
|
pDfsNameInfo->State |= DFS_VOLUME_FLAVOR_STANDALONE;
|
|
}
|
|
}
|
|
|
|
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
|
|
DfsRegistryStore::PackSetNameInformation(
|
|
IN PDFS_NAME_INFORMATION pDfsNameInfo,
|
|
IN OUT PVOID *ppBuffer,
|
|
IN OUT PULONG pSizeRemaining)
|
|
{
|
|
DFSSTATUS Status;
|
|
|
|
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,
|
|
&MiStdDfsIdProperty );
|
|
|
|
//
|
|
// Follow that info with the timeout information.
|
|
//
|
|
if ( Status == ERROR_SUCCESS )
|
|
{
|
|
Status = PackSetULong( pDfsNameInfo->Timeout,
|
|
ppBuffer,
|
|
pSizeRemaining);
|
|
}
|
|
|
|
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
|
|
DfsRegistryStore::PackSizeNameInformation(
|
|
IN PDFS_NAME_INFORMATION pDfsNameInfo )
|
|
{
|
|
ULONG Size;
|
|
|
|
Size = PackSizeInformation( (ULONG_PTR)pDfsNameInfo,
|
|
&MiStdDfsIdProperty );
|
|
|
|
Size += PackSizeULong();
|
|
|
|
return Size;
|
|
}
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// 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
|
|
DfsRegistryStore::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;
|
|
ULONG NameBlobSize, ReplicaBlobSize;
|
|
|
|
Status = CreateNameInformationBlob( pNameInfo,
|
|
&pNameBlob,
|
|
&NameBlobSize );
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = CreateReplicaListInformationBlob( pReplicaListInfo,
|
|
&pReplicaBlob,
|
|
&ReplicaBlobSize );
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = CreateNewChild( DfsHandle,
|
|
pNameBlob,
|
|
NameBlobSize,
|
|
pReplicaBlob,
|
|
ReplicaBlobSize,
|
|
pMetadataName );
|
|
|
|
ReleaseMetadataReplicaBlob( pReplicaBlob, ReplicaBlobSize );
|
|
}
|
|
ReleaseMetadataNameBlob( pNameBlob, NameBlobSize );
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
DFSSTATUS
|
|
DfsRegistryStore::CreateNewChild(
|
|
IN DFS_METADATA_HANDLE DfsHandle,
|
|
IN PVOID pNameBlob,
|
|
IN ULONG NameBlobSize,
|
|
IN PVOID pReplicaBlob,
|
|
IN ULONG ReplicaBlobSize,
|
|
IN PUNICODE_STRING pMetadataName )
|
|
{
|
|
HKEY DfsMetadataKey;
|
|
DFSSTATUS Status;
|
|
HKEY ChildKey;
|
|
DfsMetadataKey = (HKEY)ExtractFromMetadataHandle( DfsHandle );
|
|
|
|
//
|
|
// Now create the child with this name
|
|
//
|
|
Status = RegCreateKeyEx( DfsMetadataKey,
|
|
pMetadataName->Buffer,
|
|
0,
|
|
L"",
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_READ | KEY_WRITE,
|
|
NULL,
|
|
&ChildKey,
|
|
NULL );
|
|
|
|
//
|
|
// Now set the name and replica information on this newly created
|
|
// key.
|
|
//
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = SetMetadata( ChildKey,
|
|
NULL,
|
|
DfsRegistryNameString,
|
|
pNameBlob,
|
|
NameBlobSize );
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = SetMetadata( ChildKey,
|
|
NULL,
|
|
DfsRegistryReplicaString,
|
|
pReplicaBlob,
|
|
ReplicaBlobSize );
|
|
}
|
|
//
|
|
// we are done with the child key: close it here.
|
|
//
|
|
RegCloseKey (ChildKey);
|
|
|
|
//
|
|
// if we were unsuccessful in adding the name and
|
|
// replica details, get rid of the new child registry entry.
|
|
//
|
|
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
DFSSTATUS DeleteStatus;
|
|
|
|
DeleteStatus = RegDeleteKey( DfsMetadataKey,
|
|
pMetadataName->Buffer );
|
|
|
|
DFSLOG("Created Key, but failed to add values %x. Delete Status %x\n",
|
|
Status, DeleteStatus );
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
DFSSTATUS
|
|
DfsRegistryStore::RemoveChild(
|
|
IN DFS_METADATA_HANDLE DfsHandle,
|
|
LPWSTR ChildName )
|
|
|
|
{
|
|
DFSSTATUS Status;
|
|
HKEY DfsMetadataKey;
|
|
|
|
DfsMetadataKey = (HKEY)ExtractFromMetadataHandle( DfsHandle );
|
|
|
|
Status = RegDeleteKey( DfsMetadataKey,
|
|
ChildName );
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
DFSSTATUS
|
|
DfsRegistryStore::CreateStandaloneRoot(
|
|
LPWSTR MachineName,
|
|
LPWSTR LogicalShare,
|
|
LPWSTR Comment )
|
|
{
|
|
DFSSTATUS Status = ERROR_SUCCESS;
|
|
HKEY StdDfsKey = NULL;
|
|
HKEY StdDfsShareKey = NULL;
|
|
DfsRootFolder *pRootFolder = NULL;
|
|
PVOID pBlob = NULL;
|
|
ULONG BlobSize = 0;
|
|
DFS_NAME_INFORMATION NameInfo;
|
|
DFS_REPLICA_LIST_INFORMATION ReplicaListInfo;
|
|
DFS_REPLICA_INFORMATION ReplicaInfo;
|
|
UNICODE_STRING DfsMachine;
|
|
UNICODE_STRING DfsShare;
|
|
|
|
DFS_TRACE_LOW( REFERRAL_SERVER, "registry store, create root %ws\n", LogicalShare);
|
|
|
|
Status = DfsRtlInitUnicodeStringEx( &DfsMachine, MachineName );
|
|
if(Status != ERROR_SUCCESS)
|
|
{
|
|
Status = ERROR_INVALID_PARAMETER;
|
|
DFS_TRACE_ERROR_LOW( Status, REFERRAL_SERVER, "CreateStandaloneRoot, DfsRtlInitUnicodeStringEx - create root %ws, status %x\n", LogicalShare, Status);
|
|
return Status;
|
|
}
|
|
|
|
Status = DfsRtlInitUnicodeStringEx( &DfsShare, LogicalShare );
|
|
if(Status != ERROR_SUCCESS)
|
|
{
|
|
Status = ERROR_INVALID_PARAMETER;
|
|
DFS_TRACE_ERROR_LOW( Status, REFERRAL_SERVER, "CreateStandaloneRoot, DfsRtlInitUnicodeStringEx - create root %ws, status %x\n", LogicalShare, Status);
|
|
return Status;
|
|
}
|
|
|
|
RtlZeroMemory(&NameInfo, sizeof(DFS_NAME_INFORMATION));
|
|
|
|
if (DfsIsSpecialDomainShare(&DfsShare))
|
|
{
|
|
Status = ERROR_INVALID_PARAMETER;
|
|
DFS_TRACE_ERROR_LOW( Status, REFERRAL_SERVER, "registry store, Special Share - create root %ws, status %x\n", LogicalShare, Status);
|
|
return Status;
|
|
}
|
|
|
|
|
|
Status = LookupRoot( &DfsMachine,
|
|
&DfsShare,
|
|
&pRootFolder );
|
|
|
|
DFS_TRACE_LOW( REFERRAL_SERVER, "registry store, create root, lookup root %p, status %x\n", pRootFolder, Status);
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
pRootFolder->ReleaseReference();
|
|
|
|
Status = ERROR_FILE_EXISTS;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
Status = GetNewStandaloneRegistryKey( MachineName,
|
|
TRUE, // write permission required
|
|
NULL,
|
|
&StdDfsKey );
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
UNICODE_STRING LogicalName;
|
|
|
|
RtlInitUnicodeString( &LogicalName, LogicalShare );
|
|
StoreInitializeNameInformation( &NameInfo,
|
|
&LogicalName,
|
|
NULL,
|
|
Comment );
|
|
NameInfo.Type |= 0x80;
|
|
|
|
StoreInitializeReplicaInformation( &ReplicaListInfo,
|
|
&ReplicaInfo,
|
|
(MachineName == NULL) ? L"." : MachineName,
|
|
LogicalShare );
|
|
}
|
|
|
|
if (Status == ERROR_SUCCESS) {
|
|
#if defined (DFS_FUTURES)
|
|
//
|
|
// Check if we need to store the root as a guid instead of
|
|
// the root name itself.
|
|
// It is probably not necessary, but for some reason if we need
|
|
// to, we can scavenge this code.
|
|
//
|
|
//
|
|
// get an unique metadata name for the root.
|
|
//
|
|
|
|
Status = DfsGenerateUuidString(&UuidString);
|
|
#endif
|
|
|
|
Status = RegCreateKeyEx( StdDfsKey,
|
|
LogicalShare,
|
|
0,
|
|
L"",
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_READ | KEY_WRITE,
|
|
NULL,
|
|
&StdDfsShareKey,
|
|
NULL );
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
size_t LogicalShareCchLength = 0;
|
|
|
|
Status = DfsStringCchLength( LogicalShare,
|
|
MAXUSHORT,
|
|
&LogicalShareCchLength );
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
LogicalShareCchLength++; // NULL Terminator
|
|
Status = RegSetValueEx( StdDfsShareKey,
|
|
DfsRootShareValueName,
|
|
0,
|
|
REG_SZ,
|
|
(PBYTE)LogicalShare,
|
|
LogicalShareCchLength * sizeof(WCHAR) );
|
|
}
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = RegSetValueEx( StdDfsShareKey,
|
|
DfsLogicalShareValueName,
|
|
0,
|
|
REG_SZ,
|
|
(PBYTE)LogicalShare,
|
|
LogicalShareCchLength * sizeof(WCHAR) );
|
|
}
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = CreateNameInformationBlob( &NameInfo,
|
|
&pBlob,
|
|
&BlobSize);
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = SetMetadata( StdDfsShareKey,
|
|
NULL,
|
|
DfsRegistryNameString,
|
|
pBlob,
|
|
BlobSize );
|
|
ReleaseMetadataNameBlob(pBlob, BlobSize );
|
|
}
|
|
}
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = CreateReplicaListInformationBlob( &ReplicaListInfo,
|
|
&pBlob,
|
|
&BlobSize);
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = SetMetadata( StdDfsShareKey,
|
|
NULL,
|
|
DfsRegistryReplicaString,
|
|
pBlob,
|
|
BlobSize );
|
|
ReleaseMetadataNameBlob( pBlob, BlobSize );
|
|
}
|
|
}
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = GetRootFolder( MachineName,
|
|
LogicalShare,
|
|
&DfsShare,
|
|
&DfsShare,
|
|
&pRootFolder );
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Now, acquire the root share directory. If we fail
|
|
// this, we deny the creation of the root.
|
|
// acquire root share directory converts the root share
|
|
// to a physical path, checks if that supports
|
|
// reparse points, and if so tells the dfs driver
|
|
// to attach to the drive.
|
|
// if any of these fail, we cannot proceed.
|
|
//
|
|
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 Standalone Root, adding root folder status %x\n", Status);
|
|
}
|
|
|
|
RegCloseKey( StdDfsShareKey );
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
RegDeleteKey( StdDfsKey,
|
|
LogicalShare );
|
|
}
|
|
}
|
|
|
|
#if defined (DFS_FUTURES)
|
|
DfsReleaseUuidString(&UuidString);
|
|
#endif
|
|
|
|
RegCloseKey( StdDfsKey );
|
|
}
|
|
DFS_TRACE_ERROR_LOW( Status, REFERRAL_SERVER, "registry store, create root %ws, status %x\n", LogicalShare, Status);
|
|
return Status;
|
|
}
|
|
|
|
|
|
DFSSTATUS
|
|
DfsRegistryStore::DeleteStandaloneRoot(
|
|
LPWSTR MachineName,
|
|
LPWSTR LogicalShare )
|
|
|
|
{
|
|
DFSSTATUS Status = ERROR_SUCCESS;
|
|
HKEY DfsKey = NULL;
|
|
DfsRootFolder *pRootFolder = NULL;
|
|
LPWSTR RootRegistryName = NULL;
|
|
LPWSTR UseChildName = NULL;
|
|
UNICODE_STRING DfsMachine;
|
|
UNICODE_STRING DfsShare;
|
|
|
|
DFS_TRACE_LOW( REFERRAL_SERVER, "Delete Standalone root %ws\n", LogicalShare);
|
|
|
|
Status = DfsRtlInitUnicodeStringEx( &DfsMachine, MachineName );
|
|
if(Status != ERROR_SUCCESS)
|
|
{
|
|
Status = ERROR_INVALID_PARAMETER;
|
|
DFS_TRACE_ERROR_LOW( Status, REFERRAL_SERVER, "DeleteStandaloneRoot, DfsRtlInitUnicodeStringEx - create root %ws, status %x\n", LogicalShare, Status);
|
|
return Status;
|
|
}
|
|
|
|
Status = DfsRtlInitUnicodeStringEx( &DfsShare, LogicalShare );
|
|
if(Status != ERROR_SUCCESS)
|
|
{
|
|
Status = ERROR_INVALID_PARAMETER;
|
|
DFS_TRACE_ERROR_LOW( Status, REFERRAL_SERVER, "DeleteStandaloneRoot, DfsRtlInitUnicodeStringEx - create root %ws, status %x\n", LogicalShare, Status);
|
|
return Status;
|
|
}
|
|
|
|
Status = LookupRoot( &DfsMachine,
|
|
&DfsShare,
|
|
&pRootFolder );
|
|
|
|
DFS_TRACE_LOW( REFERRAL_SERVER, "Delete Standalone root, lookup root %p, status %x\n", pRootFolder, Status);
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = pRootFolder->AcquireRootLock();
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
pRootFolder->SetRootFolderDeleteInProgress();
|
|
pRootFolder->ReleaseRootLock();
|
|
}
|
|
}
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
RootRegistryName = pRootFolder->GetRootRegKeyNameString();
|
|
|
|
UseChildName = (IsEmptyString(RootRegistryName) == TRUE) ? NULL : RootRegistryName;
|
|
|
|
if (UseChildName == NULL)
|
|
{
|
|
Status = GetOldDfsRegistryKey( MachineName,
|
|
TRUE,
|
|
NULL,
|
|
&DfsKey );
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = SHDeleteKey( DfsKey,
|
|
DfsOldStandaloneChild);
|
|
|
|
RegCloseKey( DfsKey );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Status = GetNewStandaloneRegistryKey( MachineName,
|
|
TRUE,
|
|
NULL,
|
|
&DfsKey );
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = SHDeleteKey( DfsKey,
|
|
UseChildName );
|
|
|
|
RegCloseKey( DfsKey );
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// DfsDev: needs fixing.
|
|
//
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
NTSTATUS DeleteStatus;
|
|
|
|
//
|
|
// Release the root folder that we had acquired earlier for
|
|
// this root.
|
|
//
|
|
|
|
DeleteStatus = RemoveRootFolder( pRootFolder,
|
|
TRUE ); // permanent removal
|
|
|
|
DFS_TRACE_ERROR_LOW( DeleteStatus, REFERRAL_SERVER, "remove root folder %p (%ws) status %x\n", pRootFolder, LogicalShare, DeleteStatus);
|
|
|
|
|
|
DeleteStatus = pRootFolder->ReleaseRootShareDirectory();
|
|
DFS_TRACE_ERROR_LOW( DeleteStatus, REFERRAL_SERVER, "release root share for %ws status %x\n", LogicalShare, DeleteStatus);
|
|
|
|
pRootFolder->ReleaseReference();
|
|
}
|
|
|
|
DFS_TRACE_ERROR_LOW( Status, REFERRAL_SERVER, "Delete Standalone root for %ws, done, status %x\n", LogicalShare, Status);
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
DFSSTATUS
|
|
DfsRegistryStore::EnumerateApiLinks(
|
|
IN DFS_METADATA_HANDLE DfsHandle,
|
|
PUNICODE_STRING pRootName,
|
|
DWORD Level,
|
|
LPBYTE pBuffer,
|
|
LONG BufferSize,
|
|
LPDWORD pEntriesToRead,
|
|
LPDWORD pResumeHandle,
|
|
PLONG pSizeRequired )
|
|
{
|
|
HKEY DfsKey = NULL;
|
|
ULONG ChildNum = 0;
|
|
DFSSTATUS Status = ERROR_SUCCESS;
|
|
BOOLEAN OverFlow = FALSE;
|
|
LONG HeaderSize = 0;
|
|
LONG EntriesRead = 0;
|
|
LONG EntriesToRead = *pEntriesToRead;
|
|
LONG SizeRequired = 0;
|
|
LONG EntryCount = 0;
|
|
|
|
LPBYTE pLinkBuffer = NULL;
|
|
LONG LinkBufferSize = 0;
|
|
|
|
LPBYTE CurrentBuffer = NULL;
|
|
LPBYTE NewBuffer = NULL;
|
|
LONG SizeRemaining = 0;
|
|
DFSSTATUS PackStatus = ERROR_SUCCESS;
|
|
|
|
ULONG_PTR SizeDiff;
|
|
DWORD CchMaxName = 0;
|
|
DWORD CchChildName = 0;
|
|
LPWSTR ChildName = NULL;
|
|
|
|
Status = DfsApiSizeLevelHeader( Level, &HeaderSize );
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
DfsKey = (HKEY)ExtractFromMetadataHandle( DfsHandle );
|
|
|
|
OverFlow = FALSE;
|
|
|
|
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;
|
|
}
|
|
|
|
if (EntryCount == 0)
|
|
{
|
|
Status = GetStoreApiInformationBuffer ( DfsHandle,
|
|
pRootName,
|
|
NULL,
|
|
Level,
|
|
&pLinkBuffer,
|
|
&LinkBufferSize );
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
SizeRequired += ROUND_UP_COUNT(LinkBufferSize, ALIGN_QUAD);
|
|
|
|
if (OverFlow == FALSE)
|
|
{
|
|
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++;
|
|
}
|
|
}
|
|
|
|
if (Status != ERROR_SUCCESS )
|
|
{
|
|
return Status;
|
|
}
|
|
ChildNum = EntryCount - 1;
|
|
|
|
//
|
|
// First find the length of the longest subkey
|
|
// and allocate a buffer big enough for it.
|
|
//
|
|
Status = RegQueryInfoKey( DfsKey, // Key
|
|
NULL, // Class string
|
|
NULL, // Size of class string
|
|
NULL, // Reserved
|
|
NULL, // # of subkeys
|
|
&CchMaxName, // max size of subkey name in TCHARs
|
|
NULL, // max size of class name
|
|
NULL, // # of values
|
|
NULL, // max size of value name
|
|
NULL, // max size of value data,
|
|
NULL, // security descriptor
|
|
NULL ); // Last write time
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
CchMaxName++; // Space for the NULL terminator.
|
|
ChildName = (LPWSTR) new WCHAR [CchMaxName];
|
|
if (ChildName == NULL)
|
|
{
|
|
Status = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
}
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
do
|
|
{
|
|
//
|
|
// For each child, get the child name.
|
|
//
|
|
|
|
if (EntriesToRead && EntriesRead >= EntriesToRead)
|
|
{
|
|
break;
|
|
}
|
|
|
|
CchChildName = CchMaxName;
|
|
//
|
|
// Now enumerate the children, starting from the first child.
|
|
//
|
|
Status = RegEnumKeyEx( DfsKey,
|
|
ChildNum,
|
|
ChildName,
|
|
&CchChildName,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL );
|
|
|
|
ChildNum++;
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = GetStoreApiInformationBuffer( DfsHandle,
|
|
pRootName,
|
|
ChildName,
|
|
Level,
|
|
&pLinkBuffer,
|
|
&LinkBufferSize );
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
SizeRequired += ROUND_UP_COUNT(LinkBufferSize, ALIGN_QUAD);
|
|
|
|
if (OverFlow == FALSE)
|
|
{
|
|
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++;
|
|
}
|
|
}
|
|
} while (Status == ERROR_SUCCESS);
|
|
|
|
delete [] ChildName;
|
|
}
|
|
|
|
*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
|
|
DfsRegistryStore::GetMetadataNameBlob(
|
|
DFS_METADATA_HANDLE RootHandle,
|
|
LPWSTR MetadataName,
|
|
PVOID *ppData,
|
|
PULONG pDataSize,
|
|
PFILETIME pLastModifiedTime )
|
|
{
|
|
HKEY DfsMetadataKey;
|
|
DFSSTATUS Status;
|
|
|
|
DfsMetadataKey = (HKEY)ExtractFromMetadataHandle( RootHandle );
|
|
|
|
Status = GetMetadata( DfsMetadataKey,
|
|
MetadataName,
|
|
DfsRegistryNameString,
|
|
ppData,
|
|
pDataSize,
|
|
pLastModifiedTime );
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
DFSSTATUS
|
|
DfsRegistryStore::GetMetadataReplicaBlob(
|
|
DFS_METADATA_HANDLE RootHandle,
|
|
LPWSTR MetadataName,
|
|
PVOID *ppData,
|
|
PULONG pDataSize,
|
|
PFILETIME pLastModifiedTime )
|
|
{
|
|
HKEY DfsMetadataKey;
|
|
DFSSTATUS Status;
|
|
|
|
DfsMetadataKey = (HKEY)ExtractFromMetadataHandle( RootHandle );
|
|
|
|
Status = GetMetadata( DfsMetadataKey,
|
|
MetadataName,
|
|
DfsRegistryReplicaString,
|
|
ppData,
|
|
pDataSize,
|
|
pLastModifiedTime );
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
DFSSTATUS
|
|
DfsRegistryStore::SetMetadataNameBlob(
|
|
DFS_METADATA_HANDLE RootHandle,
|
|
LPWSTR MetadataName,
|
|
PVOID pData,
|
|
ULONG DataSize )
|
|
|
|
{
|
|
HKEY DfsMetadataKey;
|
|
DFSSTATUS Status;
|
|
|
|
DfsMetadataKey = (HKEY)ExtractFromMetadataHandle( RootHandle );
|
|
|
|
Status = SetMetadata( DfsMetadataKey,
|
|
MetadataName,
|
|
DfsRegistryNameString,
|
|
pData,
|
|
DataSize );
|
|
return Status;
|
|
}
|
|
|
|
|
|
DFSSTATUS
|
|
DfsRegistryStore::SetMetadataReplicaBlob(
|
|
DFS_METADATA_HANDLE RootHandle,
|
|
LPWSTR MetadataName,
|
|
PVOID pData,
|
|
ULONG DataSize )
|
|
{
|
|
HKEY DfsMetadataKey;
|
|
DFSSTATUS Status;
|
|
|
|
DfsMetadataKey = (HKEY)ExtractFromMetadataHandle( RootHandle );
|
|
|
|
Status = SetMetadata( DfsMetadataKey,
|
|
MetadataName,
|
|
DfsRegistryReplicaString,
|
|
pData,
|
|
DataSize );
|
|
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// This removes the target share from the
|
|
// Microsoft\Dfs\Roots\Domain registry key.
|
|
//
|
|
DFSSTATUS
|
|
DfsRegistryStore::CleanRegEntry(
|
|
LPWSTR MachineName,
|
|
LPWSTR LogicalShare
|
|
)
|
|
{
|
|
HKEY DfsKey;
|
|
DFSSTATUS Status;
|
|
DFSSTATUS RetStatus = ERROR_NOT_FOUND;
|
|
HKEY DfsDriverKey;
|
|
|
|
//
|
|
// If we can open the old registry key,
|
|
// then we assume we are dealing with an
|
|
// old style single root standalone system.
|
|
//
|
|
Status = GetDfsRegistryKey (MachineName,
|
|
DfsRegistryHostLocation, //DfsHost
|
|
TRUE,
|
|
NULL,
|
|
&DfsKey );
|
|
//
|
|
// Delete the \DfsHost\Volumes key and all its values.
|
|
//
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
|
|
Status = SHDeleteKey( DfsKey,
|
|
DfsVolumesLocation );
|
|
|
|
RegCloseKey( DfsKey );
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
// Something succeeded. We'll return that.
|
|
RetStatus = Status;
|
|
|
|
// Delete the DfsDriver\LocalVolumes key as well.
|
|
Status = GetDfsRegistryKey (MachineName,
|
|
DfsRegistryDfsDriverLocation, //System\CCS\Services\DfsDriver
|
|
TRUE,
|
|
NULL,
|
|
&DfsDriverKey );
|
|
//
|
|
// Delete the \LocalVolumes key and all its values.
|
|
//
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = SHDeleteKey( DfsDriverKey,
|
|
DfsLocalVolumesValue );
|
|
RegCloseKey( DfsDriverKey );
|
|
|
|
// We don't bother to recreate the DfsHost\Volumes key on error. For all external
|
|
// purposes the root should have disappeared now.
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// BUG 732833: Clean .Net location whether the Win2K location exists or not.
|
|
// We need both locations to co-exist on mix-mode cluster machines.
|
|
//
|
|
Status = GetNewStandaloneRegistryKey( MachineName,
|
|
TRUE,
|
|
NULL,
|
|
&DfsKey );
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = SHDeleteKey( DfsKey,
|
|
LogicalShare );
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
RetStatus = Status;
|
|
}
|
|
RegCloseKey( DfsKey );
|
|
}
|
|
|
|
|
|
DFS_TRACE_LOW( REFERRAL_SERVER, "registry store, CleanRegistry %ws status=%d\n", MachineName, Status);
|
|
|
|
return RetStatus;
|
|
|
|
UNREFERENCED_PARAMETER( LogicalShare );
|
|
}
|
|
|
|
|