2025-04-27 07:49:33 -04:00

1480 lines
41 KiB
C++

//+----------------------------------------------------------------------------
//
// Copyright (C) 2000, Microsoft Corporation
//
// File: DfsInit.cxx
//
// Contents: Contains initialization of server
//
// Classes: none.
//
// History: Dec. 8 2000, Author: udayh
// Jan. 12 2001, Rohanp - Added retrieval of replica data
//
//-----------------------------------------------------------------------------
#include "DfsRegistryStore.hxx"
#include "DfsADBlobStore.hxx"
#include "DfsEnterpriseStore.hxx"
#include "DfsFolderReferralData.hxx"
#include "DfsInit.hxx"
#include "DfsServerSiteInfo.hxx"
#include "DfsSiteSupport.hxx"
#include "dfsfilterapi.hxx"
#include "DfsClusterSupport.hxx"
#include "DomainControllerSupport.hxx"
#include "DfsDomainInformation.hxx"
#include "dfsadsiapi.hxx"
#include "DfsSynchronizeRoots.hxx"
#include "dfsinit.tmh"
//
// DFS_REGISTER_STORE: A convenience define to be able to register a
// number of differnet store types.
//
#define DFS_REGISTER_STORE(_name, _sts) \
{ \
DfsServerGlobalData.pDfs ## _name ## Store = new Dfs ## _name ## Store(); \
\
if (DfsServerGlobalData.pDfs ## _name ## Store == NULL) { \
(_sts) = ERROR_NOT_ENOUGH_MEMORY; \
} \
else { \
DfsServerGlobalData.pDfs ## _name ## Store->pNextRegisteredStore = DfsServerGlobalData.pRegisteredStores; \
DfsServerGlobalData.pRegisteredStores = DfsServerGlobalData.pDfs ## _name ## Store; \
(_sts) = ERROR_SUCCESS; \
} \
}
//
// INITIALIZE_COMPUTER_INFO: A convenience define to initialize the
// different information about the computer (netbios, dns, domain etc)
//
#define INITIALIZE_COMPUTER_INFO( _NamedInfo, _pBuffer, _Sz, _Sts ) \
{ \
ULONG NameSize = _Sz; \
if (_Sts == ERROR_SUCCESS) { \
DWORD dwRet = GetComputerNameEx( _NamedInfo,_pBuffer,&NameSize ); \
if (dwRet == 0) _Sts = GetLastError(); \
} \
if (_Sts == ERROR_SUCCESS) { \
LPWSTR NewName = new WCHAR [ NameSize + 1 ]; \
if (NewName == NULL) _Sts = ERROR_NOT_ENOUGH_MEMORY; \
else wcscpy( NewName, _pBuffer ); \
DfsServerGlobalData.DfsMachineInfo.Static ## _NamedInfo ## = NewName;\
} \
}
//
// The DfsServerGlobalData: the data structure that holds the registered
// stores and the registered names, among others.
//
DFS_SERVER_GLOBAL_DATA DfsServerGlobalData;
//
// Varios strings that represent the names in registry where some of
// DFS information is stored.
//
LPWSTR DfsParamPath = L"System\\CurrentControlSet\\Services\\Dfs\\Parameters";
LPWSTR DfsRegistryHostLocation = L"SOFTWARE\\Microsoft\\DfsHost";
LPWSTR DfsOldRegistryLocation = L"SOFTWARE\\Microsoft\\DfsHost\\volumes";
LPWSTR DfsVolumesLocation = L"volumes";
LPWSTR DfsOldStandaloneChild = L"domainroot";
LPWSTR DfsRegistryDfsLocation = L"SOFTWARE\\Microsoft\\Dfs";
LPWSTR DfsNewRegistryLocation = L"SOFTWARE\\Microsoft\\Dfs\\Roots";
LPWSTR DfsRootLocation=L"Roots";
LPWSTR DfsStandaloneChild = L"Standalone";
LPWSTR DfsADBlobChild = L"Domain";
LPWSTR DfsEnterpriseChild = L"Enterprise";
LPWSTR DfsRootShareValueName = L"RootShare";
LPWSTR DfsLogicalShareValueName = L"LogicalShare";
LPWSTR DfsFtDfsValueName = L"FTDfs";
LPWSTR DfsFtDfsConfigDNValueName = L"FTDfsObjectDN";
LPWSTR DfsWorkerThreadIntervalName = L"WorkerThreadInterval";
DFSSTATUS
DfsRegisterStores( VOID );
VOID
DfsRecognize( LPWSTR Name );
DFSSTATUS
DfsRegisterName(LPWSTR Name);
DWORD
DfsWorkerThread(LPVOID TData);
DFSSTATUS
DfsCreateRequiredDfsKeys(void);
BOOL
DfsGetGlobalRegistrySettings(void);
//+-------------------------------------------------------------------------
//
// Function: DfsGetRegistryStore
//
// Arguments: ppRegStore - the registered registry store.
//
// Returns: Status
// ERROR_SUCCESS on success
// ERROR status code otherwise
//
//
// Description: This routine searches through the registered stores, and
// picks the one that is the registry store. This is required for
// specific API requests that target the Registry based DFS
// For example: add standalone root, etc
//
//--------------------------------------------------------------------------
DFSSTATUS
DfsGetRegistryStore(
DfsRegistryStore **ppRegStore )
{
DFSSTATUS Status = ERROR_SUCCESS;
*ppRegStore = DfsServerGlobalData.pDfsRegistryStore;
if (*ppRegStore != NULL)
{
(*ppRegStore)->AcquireReference();
}
else
{
Status = ERROR_NOT_SUPPORTED;
}
return Status;
}
//+-------------------------------------------------------------------------
//
// Function: DfsGetADBlobStore
//
// Arguments: ppRegStore - the registered ADBlob store.
//
// Returns: Status
// ERROR_SUCCESS on success
// ERROR status code otherwise
//
//
// Description: This routine searches through the registered stores, and
// picks the one that is the registry store. This is required for
// specific API requests that target the ADBlob based DFS
// For example: add root, etc
//
//--------------------------------------------------------------------------
DFSSTATUS
DfsGetADBlobStore(
DfsADBlobStore **ppStore )
{
DFSSTATUS Status = ERROR_SUCCESS;
*ppStore = DfsServerGlobalData.pDfsADBlobStore;
if (*ppStore != NULL)
{
(*ppStore)->AcquireReference();
}
else
{
Status = ERROR_NOT_SUPPORTED;
}
return Status;
}
//+-------------------------------------------------------------------------
//
// Function: DfsServerInitialize
//
// Arguments: Flags - the server flags
//
// Returns: Status
// ERROR_SUCCESS on success
// ERROR status code otherwise
//
//
// Description: This routine initializes the DFS server. It registers
// all the different stores we care about, and also
// starts up a thread that is responsible for keeping the
// DFS info upto date.
//
//--------------------------------------------------------------------------
DFSSTATUS
DfsServerInitialize(
ULONG Flags )
{
DFSSTATUS Status = ERROR_SUCCESS;
ZeroMemory(&DfsServerGlobalData, sizeof(DfsServerGlobalData));
DfsServerGlobalData.pRegisteredStores = NULL;
DfsServerGlobalData.Flags = Flags;
InitializeCriticalSection( &DfsServerGlobalData.DataLock );
//
// Initialize the prefix table library.
//
DfsPrefixTableInit();
Status = DfsCreateRequiredDfsKeys();
//
// Create a site support class that lets us look up the server-site
// information of servers that configured in our metadata.
//
DfsServerGlobalData.pSiteSupport = new DfsSiteSupport(&Status);
DfsServerGlobalData.CacheFlushInterval = CACHE_FLUSH_INTERVAL;
DfsGetGlobalRegistrySettings();
if (Status == ERROR_SUCCESS)
{
Status = DfsRootSynchronizeInit();
DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "Initialize root synchronization status %x\n", Status);
}
//
// Now initialize the computer info, so that this server knows
// the netbios name, domain name and dns name of this machine.
//
if (Status == ERROR_SUCCESS)
{
Status = DfsInitializeComputerInfo();
DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "Initialize computer info status %x\n", Status);
}
if (Status == ERROR_SUCCESS)
{
Status = DfsClusterInit( &DfsServerGlobalData.IsCluster );
DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "Dfs Cluster Init Status %x IsCluster %d\n",
Status, DfsServerGlobalData.IsCluster);
}
if (Status == ERROR_SUCCESS)
{
Status = DfsDcInit( &DfsServerGlobalData.IsDc,
&DfsServerGlobalData.pDomainInfo );
DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "Dfs DC Init Status %x, IsDC %d\n",
Status, DfsServerGlobalData.IsDc);
}
if (Status == ERROR_SUCCESS)
{
if(!DfsIsMachineWorkstation())
{
Status = DfsGenerateDfsAdNameContext(&DfsServerGlobalData.DfsAdNameContext);
DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "DfsGenerateDfsAdNameContext Status %x\n", Status);
}
}
if ( Status == ERROR_SUCCESS )
{
Status = DfsInitializePrefixTable( &DfsServerGlobalData.pDirectoryPrefixTable,
FALSE,
NULL );
DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "Initialize directory prefix table Status %x\n", Status);
}
//
// If the flags indicate that we are handling all known local
// namespace on this machine, add an empty string to the handled
// namespace list.
//
if (Status == ERROR_SUCCESS)
{
if (Flags & DFS_LOCAL_NAMESPACE)
{
BOOLEAN Migrate;
Migrate = DfsServerGlobalData.IsCluster ? FALSE : TRUE;
Status = DfsAddHandledNamespace(L"", Migrate);
DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "DfsAddHandledNamespace Status %x\n", Status);
}
}
//
// Now register all the stores.
//
if (Status == ERROR_SUCCESS) {
Status = DfsRegisterStores();
DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "DfsRegisterStores Status %x\n", Status);
}
//
// Create our scavenge thread.
//
if (Status == ERROR_SUCCESS) {
HANDLE THandle;
DWORD Tid;
THandle = CreateThread (
NULL,
0,
DfsWorkerThread,
0,
0,
&Tid);
if (THandle != NULL) {
CloseHandle(THandle);
DFS_TRACE_HIGH(REFERRAL_SERVER, "Created Scavenge Thread (%d) Tid\n", Tid);
}
else {
Status = GetLastError();
DFS_TRACE_HIGH(REFERRAL_SERVER, "Failed Scavenge Thread creation, Status %x\n", Status);
}
}
if(Status == ERROR_SUCCESS)
{
Status = DfsInitializeReflectionEngine();
DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "Initialize Reflection Engine, Status %x\n", Status);
}
if (Status == ERROR_SUCCESS)
{
if (DfsServerGlobalData.IsDc)
{
extern DFSSTATUS DfsInitializeSpecialDCShares();
Status = DfsInitializeSpecialDCShares();
}
}
return Status;
}
//+-------------------------------------------------------------------------
//
// Function: DfsRegisterStores
//
// Arguments: NONE
//
// Returns: Status
// ERROR_SUCCESS on success
// ERROR status code otherwise
//
//
// Description: This routine registers the different stores
// that the referral library implements.
//
//--------------------------------------------------------------------------
DFSSTATUS
DfsRegisterStores(
VOID )
{
DFSSTATUS Status = ERROR_SUCCESS;
if(!DfsIsMachineWorkstation())
{
if (Status == ERROR_SUCCESS)
DFS_REGISTER_STORE(Enterprise, Status);
if (Status == ERROR_SUCCESS)
DFS_REGISTER_STORE(ADBlob, Status);
}
if (Status == ERROR_SUCCESS)
DFS_REGISTER_STORE(Registry, Status);
return Status;
}
//+-------------------------------------------------------------------------
//
// Function: DfsAddHandleNamespace
//
// Arguments: Name - namespace to add
//
// Returns: Status
// ERROR_SUCCESS on success
// ERROR status code otherwise
//
//
// Description: This routine registers the namespace, so that we handle
// referrals to that namespace. We also migrate the DFS data
// in the registry for the multiple root support. This
// happens only if the client wants to migrate DFS.
//
//--------------------------------------------------------------------------
DFSSTATUS
DfsAddHandledNamespace(
LPWSTR Name,
BOOLEAN Migrate )
{
DFSSTATUS Status = ERROR_SUCCESS;
LPWSTR NewName;
//
// allocate a new name, and copy the passed in string.
//
NewName = new WCHAR[wcslen(Name) + 1];
if (NewName == NULL)
{
Status = ERROR_NOT_ENOUGH_MEMORY;
}
if (Status == ERROR_SUCCESS) {
wcscpy( NewName, Name );
//
// always migrate the dfs to the new location.
//
if (Migrate == TRUE)
{
extern DFSSTATUS MigrateDfs(LPWSTR MachineName);
Status = MigrateDfs(NewName);
}
//
// Now register the passed in name.
//
if (Status == ERROR_SUCCESS)
{
Status = DfsRegisterName( NewName );
if (Status == ERROR_DUP_NAME)
{
delete [] NewName;
Status = ERROR_SUCCESS;
}
}
}
else {
Status = ERROR_NOT_ENOUGH_MEMORY;
}
return Status;
}
//+-------------------------------------------------------------------------
//
// Function: DfsRegisterName
//
// Arguments: Name - name to register
//
// Returns: Status
// ERROR_SUCCESS on success
// ERROR_DUP_NAME if name is already registered.
// ERROR status code otherwise
//
//
// Description: This routine registers the namespace, if it is not already
// registered.
//
//--------------------------------------------------------------------------
DFSSTATUS
DfsRegisterName(
LPWSTR Name )
{
DFSSTATUS Status = ERROR_SUCCESS;
ULONG i;
if (DfsServerGlobalData.NumberOfNamespaces > MAX_DFS_NAMESPACES)
{
Status = ERROR_INVALID_PARAMETER;
}
else
{
for (i = 0; i < DfsServerGlobalData.NumberOfNamespaces; i++)
{
if (_wcsicmp( Name,
DfsServerGlobalData.HandledNamespace[i] ) == 0)
{
Status = ERROR_DUP_NAME;
break;
}
}
if (Status == ERROR_SUCCESS)
{
DfsServerGlobalData.HandledNamespace[DfsServerGlobalData.NumberOfNamespaces++] = Name;
}
}
return Status;
}
//+-------------------------------------------------------------------------
//
// Function: DfsHandleNamespaces()
//
// Arguments: None
//
// Returns: None
//
// Description: This routine runs through all the registered names, and
// call the recognize method on each name.
//
//--------------------------------------------------------------------------
VOID
DfsHandleNamespaces()
{
ULONG i;
for (i = 0; i < DfsServerGlobalData.NumberOfNamespaces; i++) {
DFSLOG("Calling recognize on %wS\n",
DfsServerGlobalData.HandledNamespace[ i ] );
DfsRecognize( DfsServerGlobalData.HandledNamespace[ i ] );
}
return NOTHING;
}
//+-------------------------------------------------------------------------
//
// Function: DfsRecognize
//
// Arguments: Namespace
//
// Returns: None
//
// Description: This routine passes the name to each registered store
// by calling the StoreRecognize method. The store will
// decide whether any roots exist on namespace, and add
// the discovered roots to a list maintained by the store.
//
//--------------------------------------------------------------------------
VOID
DfsRecognize( LPWSTR Name )
{
DfsStore *pStore;
LPWSTR UseName = NULL;
//
// If the string is empty, we are dealing with the local case.
// Pass a null pointer, since the underlying routines expect a
// a valid machine, or a null pointer to represent the local case.
//
if (IsEmptyString(Name) == FALSE)
{
UseName = Name;
}
//
// Call the store recognizer of each registered store.
//
for (pStore = DfsServerGlobalData.pRegisteredStores;
pStore != NULL;
pStore = pStore->pNextRegisteredStore) {
DFSLOG("Calling StoreRecognizer on %wS for store %p\n",
Name, pStore );
pStore->StoreRecognizer( UseName );
}
return NOTHING;
}
VOID
DfsSynchronize()
{
DfsStore *pStore;
//
// Call the store recognizer of each registered store.
//
for (pStore = DfsServerGlobalData.pRegisteredStores;
pStore != NULL;
pStore = pStore->pNextRegisteredStore) {
DFSLOG("Calling StoreSynchronizer for store %p\n", pStore );
pStore->StoreSynchronizer();
}
return NOTHING;
}
//+-------------------------------------------------------------------------
//
// Function: DfsDumpStatistics
//
// Arguments: NONE
//
// Returns: None
//
//--------------------------------------------------------------------------
VOID
DfsDumpStatistics( )
{
DfsStore *pStore;
//
// Call the store recognizer of each registered store.
//
for (pStore = DfsServerGlobalData.pRegisteredStores;
pStore != NULL;
pStore = pStore->pNextRegisteredStore) {
pStore->DumpStatistics();
}
return NOTHING;
}
//+-------------------------------------------------------------------------
//
// Function: DfsWorkedThread
//
// Arguments: TData
//
// Returns: DWORD
//
// Description: This is the scavenge thread. It sits in a loop forever,
// waking up periodically to remove the aged referral data
// that had been cached during referral requests.
// Periodically, we call HAndleNamespaces so that the
// namespace we know of is kept in sync with the actual
// data in the respective metadata stores.
//
//--------------------------------------------------------------------------
DWORD ScavengeTime;
DWORD
DfsWorkerThread(LPVOID TData)
{
DfsFolderReferralData *pRefData = NULL;
HRESULT hr = S_OK;
HANDLE UnusedHandle = NULL;
static LoopCnt = 0;
ScavengeTime = SCAVENGE_TIME;
UNREFERENCED_PARAMETER(TData);
hr = CoInitializeEx(NULL,COINIT_MULTITHREADED| COINIT_DISABLE_OLE1DDE);
UnusedHandle = CreateEvent( NULL,
FALSE,
FALSE,
NULL );
DfsHandleNamespaces();
while (TRUE) {
DFS_TRACE_LOW( REFERRAL_SERVER, "Worker thread sleeping for %d\n", ScavengeTime);
WaitForSingleObject(UnusedHandle, ScavengeTime);
LoopCnt++;
// DfsDev: need to define a better mechanism< as to how often
// this gets to run.
//
DFS_TRACE_LOW( REFERRAL_SERVER, "Worker thread handling all namespaces\n");
DfsSynchronize();
DFS_TRACE_LOW(REFERRAL_SERVER, "Worker thread done syncing\n");
DfsDumpStatistics();
//
// now run through the loaded list and pick up aged referrals.
// and unload them.
//
do {
pRefData = NULL;
DfsRemoveReferralDataFromLoadedList( &pRefData );
if (pRefData != NULL) {
DfsFolder *pFolder = pRefData->GetOwningFolder();
pFolder->RemoveReferralData( pRefData );
pRefData->ReleaseReference();
}
} while ( pRefData != NULL );
}
CoUninitialize();
return 0;
}
//+-------------------------------------------------------------------------
//
// Function: DfsAddReferralDataToloadedList
//
// Arguments: pRefData
//
// Returns: Nothing
//
// Description: Given the referral data that was laoded, we add it
// to a loaded list, first acquiring a reference to
// it. This is effectively to keep track of the cached
// referral data in the folders.
//
// To scavenge the cache, we maintain this list, and we run
// through this list periodically freeing up aged data.
//
//--------------------------------------------------------------------------
VOID
DfsAddReferralDataToLoadedList(
DfsFolderReferralData *pRefData )
{
//
// we are going to save a pointer to the referral data.
// Acquire a reference on it
//
pRefData->AcquireReference();
//
// Now get a lock on the list, and add the ref data to the list
//
ACQUIRE_LOADED_LIST_LOCK();
if (DfsServerGlobalData.LoadedList == NULL) {
DfsServerGlobalData.LoadedList = pRefData;
pRefData->pPrevLoaded = pRefData->pNextLoaded = pRefData;
} else {
pRefData->pNextLoaded = DfsServerGlobalData.LoadedList;
pRefData->pPrevLoaded = DfsServerGlobalData.LoadedList->pPrevLoaded;
DfsServerGlobalData.LoadedList->pPrevLoaded->pNextLoaded = pRefData;
DfsServerGlobalData.LoadedList->pPrevLoaded = pRefData;
}
//
// we are done, release the list lock.
//
RELEASE_LOADED_LIST_LOCK();
}
//+-------------------------------------------------------------------------
//
// Function: DfsRemoveReferralDataFromloadedList
//
// Arguments: ppReferralData
//
// Returns: Nothing
//
// Description: This routine picks the first entry on the loaded list
// and removes it from the list and returns the referral
// data. NOTE that since we are returning the pointer,
// we do not release the reference we acquired when
// the referral data was added to the list.
//
// The caller is responsible for freeing up this reference.
//
//--------------------------------------------------------------------------
VOID
DfsRemoveReferralDataFromLoadedList(
DfsFolderReferralData **ppReferralData )
{
DfsFolderReferralData *pRefData = *ppReferralData;
ACQUIRE_LOADED_LIST_LOCK();
if (pRefData == NULL) {
pRefData = DfsServerGlobalData.LoadedList;
}
if (pRefData != NULL) {
if (pRefData->pNextLoaded == pRefData) {
DfsServerGlobalData.LoadedList = NULL;
} else {
pRefData->pNextLoaded->pPrevLoaded = pRefData->pPrevLoaded;
pRefData->pPrevLoaded->pNextLoaded = pRefData->pNextLoaded;
if (DfsServerGlobalData.LoadedList == pRefData) {
DfsServerGlobalData.LoadedList = pRefData->pNextLoaded;
}
}
}
*ppReferralData = pRefData;
RELEASE_LOADED_LIST_LOCK();
}
//+-------------------------------------------------------------------------
//
// Function: DfsGetServerInfo
//
// Arguments: pServer, ppInfo
//
// Returns: Status
//
// Description: This routine takes a server name and returns the
// structure that holds the site information for that server
//
// A referenced pointer is returned and the caller is
// required to release the reference when done.
//
//--------------------------------------------------------------------------
DFSSTATUS
DfsGetServerInfo (
PUNICODE_STRING pServer,
DfsServerSiteInfo **ppInfo )
{
return DfsServerGlobalData.pSiteSupport->GetServerSiteInfo(pServer, ppInfo );
}
//+-------------------------------------------------------------------------
//
// Function: DfsReleaseServerInfo
//
// Arguments: pInfo
//
// Returns: Nothing
//
// Description: This routine releases a server info that was earlier
// got by calling GetServerInfo
//
//--------------------------------------------------------------------------
DFSSTATUS
DfsReleaseServerInfo (
DfsServerSiteInfo *pInfo)
{
return DfsServerGlobalData.pSiteSupport->ReleaseServerSiteInfo(pInfo);
}
//+-------------------------------------------------------------------------
//
// Function: DfsInitializeComputerInfo
//
// Arguments: NOTHING
//
// Returns: Status
//
// Description: This routine initializes the computer info, which contains the domain name
// of this computer, the netbios name and dns names of this computer.
//
//--------------------------------------------------------------------------
DFSSTATUS
DfsInitializeComputerInfo()
{
#define COMPUTER_NAME_BUFFER_SIZE 2048
LONG BufferSize;
LPWSTR NameBuffer;
DFSSTATUS Status = ERROR_SUCCESS ;
BufferSize = COMPUTER_NAME_BUFFER_SIZE;
NameBuffer = new WCHAR [ BufferSize ];
if (NameBuffer != NULL)
{
INITIALIZE_COMPUTER_INFO( ComputerNameNetBIOS, NameBuffer, BufferSize, Status );
INITIALIZE_COMPUTER_INFO( ComputerNameDnsFullyQualified, NameBuffer, BufferSize, Status );
INITIALIZE_COMPUTER_INFO( ComputerNameDnsDomain, NameBuffer, BufferSize, Status );
delete [] NameBuffer;
}
else {
Status = ERROR_NOT_ENOUGH_MEMORY;
}
return Status;
}
DFSSTATUS
DfsCreateRequiredOldDfsKeys(void)
{
DFSSTATUS Status = ERROR_SUCCESS;
HKEY RootKey, DfsLocationKey, DfsVolumesKey;
Status = RegConnectRegistry( NULL,
HKEY_LOCAL_MACHINE,
&RootKey );
if(Status == ERROR_SUCCESS)
{
Status = RegCreateKeyEx( RootKey, // the parent key
DfsRegistryHostLocation, // the key we are creating.
0,
L"",
REG_OPTION_NON_VOLATILE,
KEY_READ | KEY_WRITE,
NULL,
&DfsLocationKey,
NULL );
RegCloseKey(RootKey);
if (Status == ERROR_SUCCESS)
{
Status = RegCreateKeyEx( DfsLocationKey, // the parent key
DfsVolumesLocation, // the key we are creating.
0,
L"",
REG_OPTION_NON_VOLATILE,
KEY_READ | KEY_WRITE,
NULL,
&DfsVolumesKey,
NULL );
if (Status == ERROR_SUCCESS)
{
RegCloseKey(DfsVolumesKey);
}
RegCloseKey(DfsLocationKey);
}
}
return Status;
}
DFSSTATUS
DfsCreateRequiredDfsKeys(void)
{
DFSSTATUS Status = ERROR_SUCCESS;
HKEY RootKey, DfsLocationKey, DfsRootsKey, FlavorKey;
Status = DfsCreateRequiredOldDfsKeys();
if (Status != ERROR_SUCCESS)
{
return Status;
}
Status = RegConnectRegistry( NULL,
HKEY_LOCAL_MACHINE,
&RootKey );
if(Status == ERROR_SUCCESS)
{
Status = RegCreateKeyEx( RootKey, // the parent key
DfsRegistryDfsLocation, // the key we are creating.
0,
L"",
REG_OPTION_NON_VOLATILE,
KEY_READ | KEY_WRITE,
NULL,
&DfsLocationKey,
NULL );
RegCloseKey(RootKey);
if (Status == ERROR_SUCCESS)
{
Status = RegCreateKeyEx( DfsLocationKey, // the parent key
DfsRootLocation, // the key we are creating.
0,
L"",
REG_OPTION_NON_VOLATILE,
KEY_READ | KEY_WRITE,
NULL,
&DfsRootsKey,
NULL );
RegCloseKey(DfsLocationKey);
if (Status == ERROR_SUCCESS)
{
Status = RegCreateKeyEx( DfsRootsKey, // the parent key
DfsStandaloneChild,
0,
L"",
REG_OPTION_NON_VOLATILE,
KEY_READ | KEY_WRITE,
NULL,
&FlavorKey,
NULL );
if (Status == ERROR_SUCCESS)
{
RegCloseKey(FlavorKey);
}
if (Status == ERROR_SUCCESS)
{
Status = RegCreateKeyEx( DfsRootsKey, // the parent key
DfsADBlobChild,
0,
L"",
REG_OPTION_NON_VOLATILE,
KEY_READ | KEY_WRITE,
NULL,
&FlavorKey,
NULL );
}
if (Status == ERROR_SUCCESS)
{
RegCloseKey(FlavorKey);
}
RegCloseKey( DfsRootsKey );
}
}
}
return Status;
}
DFSSTATUS
DfsGetMachineName(
PUNICODE_STRING pName)
{
DFSSTATUS Status;
LPWSTR UseName;
if (!IsEmptyString(DfsServerGlobalData.DfsMachineInfo.StaticComputerNameNetBIOS))
{
UseName = DfsServerGlobalData.DfsMachineInfo.StaticComputerNameNetBIOS;
}
else {
UseName = DfsServerGlobalData.DfsMachineInfo.StaticComputerNameDnsFullyQualified;
}
Status = DfsCreateUnicodeStringFromString( pName,
UseName );
return Status;
}
VOID
DfsReleaseMachineName(
PUNICODE_STRING pName )
{
DfsFreeUnicodeString( pName );
}
DFSSTATUS
DfsGetDomainName(
PUNICODE_STRING pName)
{
DFSSTATUS Status;
LPWSTR UseName;
if (!IsEmptyString(DfsServerGlobalData.DomainNameFlat.Buffer))
{
UseName = DfsServerGlobalData.DomainNameFlat.Buffer;
}
else if (!IsEmptyString(DfsServerGlobalData.DomainNameDns.Buffer))
{
UseName = DfsServerGlobalData.DomainNameDns.Buffer;
}
else
{
UseName = DfsServerGlobalData.DfsMachineInfo.StaticComputerNameDnsDomain;
}
Status = DfsCreateUnicodeStringFromString( pName,
UseName );
return Status;
}
VOID
DfsReleaseDomainName(
PUNICODE_STRING pName )
{
DfsFreeUnicodeString( pName );
}
DFSSTATUS
DfsAddKnownDirectoryPath(
PUNICODE_STRING pDirectoryName,
PUNICODE_STRING pLogicalShare )
{
DFSSTATUS Status = ERROR_SUCCESS;
NTSTATUS NtStatus;
UNICODE_STRING RemainingName;
PVOID pData;
BOOLEAN SubStringMatch = FALSE;
NtStatus = DfsPrefixTableAcquireWriteLock( DfsServerGlobalData.pDirectoryPrefixTable );
if ( NtStatus == STATUS_SUCCESS )
{
NtStatus = DfsFindUnicodePrefixLocked( DfsServerGlobalData.pDirectoryPrefixTable,
pDirectoryName,
&RemainingName,
&pData,
&SubStringMatch );
#if 0
//
// Note that the following comment and the logic dont work.
// we have an issue where someone could be adding the same share
// once for ft and once for standalone.
// blocking this at the api level may not be the right thing, since
// things may be added to the registry dynamically (cluster
// checkpoint) and these may not come in via the API.
//
//
// check if we have a matching name with the exact same share:
// in that case return success.
// In all other cases, return failure.
// If nothing exists by this name, we try to insert in our table.
//
if ((NtStatus == STATUS_SUCCESS) &&
(RemainingName.Length == 0))
{
PUNICODE_STRING pShare = (PUNICODE_STRING)pData;
if (RtlCompareUnicodeString(pShare, pLogicalShare, TRUE) != 0)
{
NtStatus = STATUS_OBJECT_NAME_COLLISION;
}
}
else
#endif
if ( (NtStatus == STATUS_SUCCESS) ||
((NtStatus != STATUS_SUCCESS) && (SubStringMatch)) )
{
NtStatus = STATUS_OBJECT_NAME_COLLISION;
}
else
{
//
// Insert the directory and share information in our
// database.
//
NtStatus = DfsInsertInPrefixTableLocked(DfsServerGlobalData.pDirectoryPrefixTable,
pDirectoryName,
(PVOID)pLogicalShare);
}
DfsPrefixTableReleaseLock( DfsServerGlobalData.pDirectoryPrefixTable );
}
if(NtStatus != STATUS_SUCCESS)
{
Status = RtlNtStatusToDosError(NtStatus);
}
return Status;
}
DFSSTATUS
DfsRemoveKnownDirectoryPath(
PUNICODE_STRING pDirectoryName,
PUNICODE_STRING pLogicalShare)
{
DFSSTATUS Status = ERROR_SUCCESS;
NTSTATUS NtStatus;
UNICODE_STRING RemainingName;
PVOID pData;
BOOLEAN SubStringMatch;
NtStatus = DfsPrefixTableAcquireWriteLock( DfsServerGlobalData.pDirectoryPrefixTable );
if ( NtStatus == STATUS_SUCCESS )
{
NtStatus = DfsFindUnicodePrefixLocked( DfsServerGlobalData.pDirectoryPrefixTable,
pDirectoryName,
&RemainingName,
&pData,
&SubStringMatch );
//
// if we found a perfect match, we can remove this
// from the table.
//
if ( (NtStatus == STATUS_SUCCESS) &&
(RemainingName.Length == 0) )
{
NtStatus = DfsRemoveFromPrefixTableLocked( DfsServerGlobalData.pDirectoryPrefixTable,
pDirectoryName,
(PVOID)pLogicalShare);
}
else
{
NtStatus = STATUS_OBJECT_NAME_NOT_FOUND;
}
DfsPrefixTableReleaseLock( DfsServerGlobalData.pDirectoryPrefixTable );
}
if (NtStatus != STATUS_SUCCESS)
{
Status = RtlNtStatusToDosError(NtStatus);
}
return Status;
}
//
// Function AcquireLock: Acquires the lock on the folder
//
DFSSTATUS
DfsAcquireWriteLock(
PCRITICAL_SECTION pLock)
{
DFSSTATUS Status;
__try
{
EnterCriticalSection(pLock);
Status = ERROR_SUCCESS;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
Status = GetExceptionCode();
}
return Status;
}
DFSSTATUS
DfsAcquireReadLock(
PCRITICAL_SECTION pLock)
{
DFSSTATUS Status;
__try
{
EnterCriticalSection(pLock);
Status = ERROR_SUCCESS;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
Status = GetExceptionCode();
}
return Status;
}
DFSSTATUS
DfsAcquireDomainInfo (
DfsDomainInformation **ppDomainInfo )
{
DFSSTATUS Status;
Status = DfsAcquireGlobalDataLock();
if (Status == ERROR_SUCCESS)
{
*ppDomainInfo = DfsServerGlobalData.pDomainInfo;
if (*ppDomainInfo == NULL)
{
Status = ERROR_NOT_READY;
}
else
{
(*ppDomainInfo)->AcquireReference();
}
DfsReleaseGlobalDataLock();
}
return Status;
}
VOID
DfsReleaseDomainInfo (
DfsDomainInformation *pDomainInfo )
{
pDomainInfo->ReleaseReference();
return NOTHING;
}
DFSSTATUS
DfsSetDomainNameFlat(LPWSTR DomainNameFlatString)
{
UNICODE_STRING DomainNameFlat;
RtlInitUnicodeString( &DomainNameFlat, DomainNameFlatString);
return DfsCreateUnicodeString( &DfsServerGlobalData.DomainNameFlat,
&DomainNameFlat );
}
DFSSTATUS
DfsSetDomainNameDns( LPWSTR DomainNameDnsString )
{
UNICODE_STRING DomainNameDns;
RtlInitUnicodeString( &DomainNameDns, DomainNameDnsString);
return DfsCreateUnicodeString( &DfsServerGlobalData.DomainNameDns,
&DomainNameDns);
}
BOOLEAN
DfsIsNameContextDomainName( PUNICODE_STRING pName )
{
BOOLEAN ReturnValue = FALSE;
if (pName->Length == DfsServerGlobalData.DomainNameFlat.Length)
{
if (_wcsnicmp(DfsServerGlobalData.DomainNameFlat.Buffer,
pName->Buffer, pName->Length/sizeof(WCHAR)) == 0)
{
ReturnValue = TRUE;
}
}
else if (pName->Length == DfsServerGlobalData.DomainNameDns.Length)
{
if (_wcsnicmp(DfsServerGlobalData.DomainNameDns.Buffer,
pName->Buffer, pName->Length/sizeof(WCHAR)) == 0)
{
ReturnValue = TRUE;
}
}
return ReturnValue;
}
DWORD DfsReadRegistryDword( HKEY hkey,
LPWSTR pszValueName,
DWORD dwDefaultValue )
{
DWORD dwerr = 0;
DWORD dwBuffer = 0;
DWORD cbBuffer = sizeof(dwBuffer);
DWORD dwType = 0;
if( hkey != NULL )
{
dwerr = RegQueryValueEx( hkey,
pszValueName,
NULL,
&dwType,
(LPBYTE)&dwBuffer,
&cbBuffer );
if( ( dwerr == NO_ERROR ) && ( dwType == REG_DWORD ) )
{
dwDefaultValue = dwBuffer;
}
}
return dwDefaultValue;
}
BOOL DfsGetGlobalRegistrySettings(void)
{
BOOL fRet = TRUE;
HKEY hkeyDfs = NULL;
DWORD dwErr = 0;
DWORD dwDisp = 0;
dwErr = RegCreateKeyEx(HKEY_LOCAL_MACHINE, DfsParamPath, NULL, NULL,
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkeyDfs, &dwDisp);
if (dwErr != ERROR_SUCCESS)
{
SetLastError(dwErr);
return FALSE;
}
DfsServerGlobalData.CacheFlushInterval = DfsReadRegistryDword(hkeyDfs, DfsWorkerThreadIntervalName, CACHE_FLUSH_INTERVAL);
RegCloseKey(hkeyDfs);
return fRet;
}
DFSSTATUS
DfsGetBlobDCName(
PUNICODE_STRING pDCName )
{
PDOMAIN_CONTROLLER_INFO pDomainControllerInfo = NULL;
DFSSTATUS Status;
Status = DsGetDcName( NULL, //computer name
NULL, // domain name
NULL, // domain guid
NULL, // site name
DS_PDC_REQUIRED,
&pDomainControllerInfo );
if (Status == ERROR_SUCCESS)
{
Status = DfsCreateUnicodeStringFromString( pDCName,
&pDomainControllerInfo->DomainControllerName[2] );
NetApiBufferFree(pDomainControllerInfo);
}
return Status;
}
VOID
DfsReleaseBlobDCName(
PUNICODE_STRING pDCName )
{
DfsFreeUnicodeString( pDCName );
}
BOOLEAN
DfsIsTargetCurrentMachine (
PUNICODE_STRING pServer )
{
UNICODE_STRING MachineName;
DFSSTATUS Status;
BOOLEAN ReturnValue = FALSE;
Status = DfsGetMachineName(&MachineName);
if (Status == ERROR_SUCCESS)
{
if (RtlCompareUnicodeString( pServer, &MachineName, TRUE) == 0)
{
ReturnValue = TRUE;
}
DfsFreeUnicodeString( &MachineName );
}
return ReturnValue;
}
LPWSTR
DfsGetDfsAdNameContextString()
{
return DfsServerGlobalData.DfsAdNameContext.Buffer;
}