1480 lines
41 KiB
C++
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;
|
|
}
|
|
|