Leaked source code of windows server 2003
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.
 
 
 
 
 
 

3203 lines
93 KiB

//+----------------------------------------------------------------------------
//
// 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 "DfsRegStrings.hxx"
#include "DfsRegistryStore.hxx"
#include "DfsADBlobStore.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 "DfsSiteCache.hxx"
#include "DfsSiteNameSupport.hxx"
#include "DfsISTGSupport.hxx"
#include "DfsReparse.hxx"
#include "dfsinit.tmh"
#include <dsrole.h>
#include "dfscompat.hxx"
#include "dfssecurity.h"
#include "ntlsa.h"
//
// DFS_REGISTER_STORE: A convenience define to be able to register a
// number of differnet store types.
//
#define DFS_REGISTER_STORE(_name, _sts) \
{ \
DFSSTATUS LocalStatus = ERROR_SUCCESS; \
DfsServerGlobalData.pDfs ## _name ## Store = new Dfs ## _name ## Store(&LocalStatus); \
\
if (DfsServerGlobalData.pDfs ## _name ## Store == NULL) { \
(_sts) = ERROR_NOT_ENOUGH_MEMORY; \
} \
else if (LocalStatus == ERROR_SUCCESS){ \
DfsServerGlobalData.pDfs ## _name ## Store->pNextRegisteredStore = DfsServerGlobalData.pRegisteredStores; \
DfsServerGlobalData.pRegisteredStores = DfsServerGlobalData.pDfs ## _name ## Store; \
(_sts) = ERROR_SUCCESS; \
} \
else \
{ \
(_sts) = LocalStatus; \
} \
}
//
// 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 NumChars = _Sz; \
if (_Sts == ERROR_SUCCESS) { \
DWORD dwRet = GetComputerNameEx( _NamedInfo,_pBuffer,&NumChars ); \
if (dwRet == 0) _Sts = GetLastError(); \
} \
if (_Sts == ERROR_SUCCESS) { \
LPWSTR NewName = new WCHAR [ NumChars + 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 DfsSvcPath = DFS_REG_SVC_PATH;
LPWSTR DfsDnsConfigValue = DFS_REG_DNS_CONFIG_VALUE;
LPWSTR DfsParamPath = DFS_REG_PARAM_PATH;
LPWSTR DfsRegistryHostLocation = DFS_REG_HOST_LOCATION;
LPWSTR DfsOldRegistryLocation = DFS_REG_OLD_HOST_LOCATION;
LPWSTR DfsVolumesLocation = DFS_REG_VOLUMES_LOCATION;
LPWSTR DfsOldStandaloneChild = DFS_REG_OLD_STANDALONE_CHILD;
LPWSTR DfsRegistryDfsLocation = DFS_REG_DFS_LOCATION;
LPWSTR DfsNewRegistryLocation = DFS_REG_NEW_DFS_LOCATION;
LPWSTR DfsRootLocation = DFS_REG_ROOT_LOCATION;
LPWSTR DfsStandaloneChild = DFS_REG_STANDALONE_CHILD;
LPWSTR DfsADBlobChild = DFS_REG_AD_BLOB_CHILD;
LPWSTR DfsRootShareValueName = DFS_REG_ROOT_SHARE_VALUE;
LPWSTR DfsMigratedValueName = DFS_REG_MIGRATED_VALUE;
LPWSTR DfsLogicalShareValueName = DFS_REG_LOGICAL_SHARE_VALUE;
LPWSTR DfsFtDfsValueName = DFS_REG_FT_DFS_VALUE;
LPWSTR DfsFtDfsConfigDNValueName = DFS_REG_FT_DFS_CONFIG_DN_VALUE;
LPWSTR DfsWorkerThreadIntervalName = DFS_SYNC_INTERVAL_NAME;
LPWSTR DfsSiteSupportRefreshIntervalName = DFS_REG_SITE_SUPPORT_REFRESH_INTERVAL_NAME;
LPWSTR DfsSiteIpCacheTrimValueName = DFS_REG_SITE_IP_CACHE_TRIM_VALUE;
LPWSTR DfsAllowableErrorsValueName = DFS_REG_ALLOWABLE_ERRORS_VALUE;
LPWSTR DfsLdapTimeoutValueName = DFS_REG_LDAP_TIMEOUT_VALUE;
LPWSTR DfsSiteCostedReferralsValueName = DFS_REG_SITE_COSTED_REFERRALS_VALUE;
LPWSTR DfsInsiteReferralsValueName = DFS_REG_INSITE_REFERRALS_VALUE;
LPWSTR DfsMaxClientSiteValueName = DFS_REG_MAXSITE_VALUE;
LPWSTR DfsQuerySiteCostTimeoutName = DFS_REG_QUERY_SITECOST_TIMEOUT_NAME;
LPWSTR DfsDomainNameRefreshInterval = DFS_REG_DOMAIN_NAME_REFRESH_INTERVAL_NAME;
static SECURITY_DESCRIPTOR AdminSecurityDesc;
static GENERIC_MAPPING AdminGenericMapping = {
STANDARD_RIGHTS_READ, // Generic read
STANDARD_RIGHTS_WRITE, // Generic write
STANDARD_RIGHTS_EXECUTE, // Generic execute
STANDARD_RIGHTS_READ | // Generic all
STANDARD_RIGHTS_WRITE |
STANDARD_RIGHTS_EXECUTE
};
DFSSTATUS
DfsRegisterStores( VOID );
DFSSTATUS
DfsRecognize( LPWSTR Name );
DFSSTATUS
DfsRegisterName(LPWSTR Name);
DWORD
DfsWorkerThread(LPVOID TData);
DFSSTATUS
DfsCreateRequiredDfsKeys(void);
BOOLEAN
DfsGetGlobalRegistrySettings(void);
BOOLEAN
DfsGetStaticGlobalRegistrySettings(void);
BOOLEAN
DfsInitializeSecurity();
DWORD
DfsSiteSupportThread(LPVOID TData);
VOID
StartPreloadingServerSiteData(void);
DFSSTATUS
DfsSetupPrivileges (void);
extern
DFSSTATUS
DfsGetRootReferralDataEx(
PUNICODE_STRING pName,
PUNICODE_STRING pRemainingName,
DfsFolderReferralData **ppReferralData,
PBOOLEAN pCacheHit);
//+-------------------------------------------------------------------------
//
// 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;
}
BOOL
IsStandardServerSKU(
PBOOL pIsServer
)
{
BOOL fReturnValue = (BOOL) FALSE;
OSVERSIONINFOEX VersionInfo;
BOOL IsServer = FALSE;
//
// get the current SKU.
//
VersionInfo.dwOSVersionInfoSize = sizeof(VersionInfo);
if (GetVersionEx((OSVERSIONINFO *)&VersionInfo))
{
fReturnValue = TRUE;
//
// is it some sort of server SKU?
//
if (VersionInfo.wProductType != VER_NT_WORKSTATION)
{
//
// standard server or a server variant?
//
if ((VersionInfo.wSuiteMask & (VER_SUITE_ENTERPRISE | VER_SUITE_DATACENTER)) == 0)
{
//
// it's standard server
//
IsServer = TRUE;
}
}
*pIsServer = IsServer;
}
return(fReturnValue);
}
//+-------------------------------------------------------------------------
//
// 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;
BOOLEAN fSecurity = FALSE;
BOOL fCritInit = FALSE;
BOOL fIsStandardServer = TRUE;
WSADATA wsadata;
ZeroMemory(&DfsServerGlobalData, sizeof(DfsServerGlobalData));
DfsServerGlobalData.pRegisteredStores = NULL;
DfsServerGlobalData.Flags = Flags;
DfsServerGlobalData.bDfsAdAlive = TRUE;
DfsServerGlobalData.bIsShuttingDown = FALSE;
DfsServerGlobalData.ServiceState = SERVICE_START_PENDING;
IsStandardServerSKU(&fIsStandardServer);
if(fIsStandardServer)
{
DfsServerGlobalData.bLimitRoots = TRUE;
}
DfsSetupPrivileges ();
Status = WSAStartup( MAKEWORD( 1, 1 ), &wsadata );
if(Status != 0)
{
DfsLogDfsEvent(DFS_ERROR_WINSOCKINIT_FAILED, 0, NULL, Status);
DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "[%!FUNC!- Level %!LEVEL!] WSAStartup failed status %x\n", Status);
goto Exit;
}
fSecurity = DfsInitializeSecurity();
if(fSecurity == FALSE)
{
Status = GetLastError();
DfsLogDfsEvent(DFS_ERROR_SECURITYINIT_FAILED, 0, NULL, Status);
DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "[%!FUNC!- Level %!LEVEL!]DfsInitializeSecurity failed status %x\n", Status);
goto Exit;
}
InitializeListHead(&DfsServerGlobalData.ReparseVolumeList);
InitializeListHead(&DfsServerGlobalData.SiteCostTableMruList);
DfsServerGlobalData.NumSiteCostTables = 0;
// The following are statistics we keep around, primarily for diagnostic purposes.
// There might be a better place for these. xxxdfsdev
DfsServerGlobalData.NumDfsSites = 0;
DfsServerGlobalData.NumClientDfsSiteEntries = 0;
DfsServerGlobalData.NumServerDfsSiteEntries = 0;
DfsServerGlobalData.NumDfsSitesInCache = 0; // not the same as NumDfsSites because of refcounts
DfsServerGlobalData.NumSiteCostTablesOnMruList = 0;
//
// Create and initialize the cache that maps incoming IP addresses to their corresponding
// DfsSites.
//
DfsServerGlobalData.pClientSiteSupport = DfsSiteNameCache::CreateSiteHashTable(&Status);
if(DfsServerGlobalData.pClientSiteSupport == NULL)
{
DfsLogDfsEvent(DFS_ERROR_SITECACHEINIT_FAILED, 0, NULL, Status);
DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "[%!FUNC!- Level %!LEVEL!]DfsSiteNameCache::CreateSiteHashTable failed status %x\n", Status);
goto Exit;
}
//
// Create and initialize the repository of known DfsSites indexed by their site names.
//
DfsServerGlobalData.pSiteNameSupport = DfsSiteNameSupport::CreateSiteNameSupport( &Status );
if(DfsServerGlobalData.pSiteNameSupport == NULL)
{
DfsLogDfsEvent(DFS_ERROR_SITECACHEINIT_FAILED, 0, NULL, Status); // dfsdev: insert unique error code.
DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "[%!FUNC!- Level %!LEVEL!]DfsSiteNameSupport::CreateSiteNameSupport failed status %x\n", Status);
goto Exit;
}
//
// Create a default DfsSite with a NULL sitename that we will always keep around..
//
DfsServerGlobalData.pDefaultSite = DfsSite::CreateDfsSite( &Status );
if(DfsServerGlobalData.pDefaultSite == NULL)
{
Status = ERROR_NOT_ENOUGH_MEMORY;
DfsLogDfsEvent(DFS_ERROR_SITECACHEINIT_FAILED, 0, NULL, Status); // dfsdev: insert unique error code.
DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "[%!FUNC!- Level %!LEVEL!]Default DFS site creation failed with status %x\n",
Status);
goto Exit;
}
fCritInit = InitializeCriticalSectionAndSpinCount( &DfsServerGlobalData.DataLock, DFS_CRIT_SPIN_COUNT );
if(!fCritInit)
{
Status = GetLastError();
goto Exit;
}
DfsServerGlobalData.ShutdownHandle = CreateEvent( NULL,
TRUE,
FALSE,
NULL );
if(DfsServerGlobalData.ShutdownHandle == NULL)
{
Status = GetLastError();
DfsLogDfsEvent(DFS_ERROR_CREATEEVENT_FAILED, 0, NULL, Status);
DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "[%!FUNC!- Level %!LEVEL!]CreateEvent failed status %x\n", Status);
goto Exit;
}
DfsServerGlobalData.RegNotificationHandle = CreateEvent( NULL, FALSE, FALSE, NULL );
if(DfsServerGlobalData.RegNotificationHandle == NULL)
{
Status = GetLastError();
DfsLogDfsEvent(DFS_ERROR_CREATEEVENT_FAILED, 0, NULL, Status);
DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "[%!FUNC!- Level %!LEVEL!]CreateEvent2 failed status %x\n", Status);
goto Exit;
}
//
// 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.pServerSiteSupport = DfsSiteSupport::DfsCreateSiteSupport(&Status);
if(DfsServerGlobalData.pServerSiteSupport == NULL)
{
DfsLogDfsEvent(DFS_ERROR_SITESUPPOR_FAILED, 0, NULL, Status);
goto Exit;
}
DfsServerGlobalData.CacheFlushInterval = CACHE_FLUSH_INTERVAL;
DfsGetStaticGlobalRegistrySettings();
DfsGetGlobalRegistrySettings();
Status = DfsRootSynchronizeInit();
if(Status != ERROR_SUCCESS)
{
DfsLogDfsEvent(DFS_ERROR_ROOTSYNCINIT_FAILED, 0, NULL, Status);
DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "[%!FUNC!- Level %!LEVEL!]Initialize root synchronization status %x\n", Status);
goto Exit;
}
//
// Now initialize the computer info, so that this server knows
// the netbios name, domain name and dns name of this machine.
//
Status = DfsInitializeComputerInfo();
if(Status != ERROR_SUCCESS)
{
DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "[%!FUNC!- Level %!LEVEL!]Initialize computer info status %x\n", Status);
DfsLogDfsEvent(DFS_ERROR_COMPUTERINFO_FAILED, 0, NULL, Status);
goto Exit;
}
Status = DfsClusterInit( &DfsServerGlobalData.IsCluster );
if (Status != ERROR_SUCCESS)
{
DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "[%!FUNC!- Level %!LEVEL!]Dfs Cluster Init Status %x IsCluster %d\n",
Status, DfsServerGlobalData.IsCluster);
DfsLogDfsEvent(DFS_ERROR_CLUSTERINFO_FAILED, 0, NULL, Status);
goto Exit;
}
Status = DfsDcInit( &DfsServerGlobalData.IsDc);
if (Status != ERROR_SUCCESS)
{
DfsLogDfsEvent(DFS_ERROR_DCINFO_FAILED, 0, NULL, Status);
DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "[%!FUNC!- Level %!LEVEL!]Dfs DC Init Status %x, IsDC %d\n",
Status, DfsServerGlobalData.IsDc);
goto Exit;
}
//
// We always create the ISTGHandleSupport instance, but the actual Bind call to the Ds won't
// happen until we need it. This is because at this point we just don't know if any of the roots
// has site-costing enabled or not.
//
Status = DfsISTGHandleSupport::DfsCreateISTGHandleSupport( &DfsServerGlobalData.pISTGHandleSupport );
if (Status != ERROR_SUCCESS)
{
DfsLogDfsEvent(DFS_ERROR_DCINFO_FAILED, 0, NULL, Status); // xxx dfsdev: add new error
DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "[%!FUNC!- Level %!LEVEL!]Dfs ISTGHandle creation Status %x\n",
Status);
goto Exit;
}
Status = DfsInitializePrefixTable( &DfsServerGlobalData.pDirectoryPrefixTable,
FALSE,
NULL );
if ( Status != ERROR_SUCCESS )
{
DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "[%!FUNC!- Level %!LEVEL!]Initialize directory prefix table Status %x\n", Status);
DfsLogDfsEvent(DFS_ERROR_PREFIXTABLE_FAILED, 0, NULL, Status);
goto Exit;
}
DfsServerGlobalData.pRootReferralTable = NULL;
if (DfsServerGlobalData.IsDc == TRUE)
{
Status = DfsInitializePrefixTable( &DfsServerGlobalData.pRootReferralTable,
FALSE,
NULL );
if ( Status != ERROR_SUCCESS )
{
DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "[%!FUNC!- Level %!LEVEL!]Initialize Root Referral table Status %x\n", Status);
DfsLogDfsEvent(DFS_ERROR_PREFIXTABLE_FAILED, 0, NULL, Status);
return 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 (Flags & DFS_LOCAL_NAMESPACE)
{
Status = DfsAddHandledNamespace(L"", TRUE);
if (Status != ERROR_SUCCESS)
{
DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "[%!FUNC!- Level %!LEVEL!]DfsAddHandledNamespace Status %x\n", Status);
DfsLogDfsEvent(DFS_ERROR_HANDLENAMESPACE_FAILED, 0, NULL, Status);
goto Exit;
}
}
//
// Now register all the stores.
//
Status = DfsRegisterStores();
if (Status != ERROR_SUCCESS)
{
DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "[%!FUNC!- Level %!LEVEL!]DfsRegisterStores Status %x\n", Status);
DfsLogDfsEvent(DFS_ERROR_REGISTERSTORE_FAILED, 0, NULL, Status);
goto Exit;
}
//
// Create our sitesupport thread.
//
DWORD Tid;
DfsServerGlobalData.SiteSupportThreadHandle = CreateThread (
NULL,
0,
DfsSiteSupportThread,
0,
CREATE_SUSPENDED,
&Tid);
if (DfsServerGlobalData.SiteSupportThreadHandle != NULL)
{
DFS_TRACE_HIGH(REFERRAL_SERVER, "[%!FUNC!- Level %!LEVEL!]Created DfsSiteSupportThread (%d) Tid\n", Tid);
}
else
{
Status = GetLastError();
DFS_TRACE_HIGH(REFERRAL_SERVER, "[%!FUNC!- Level %!LEVEL!]Failed DfsSiteSupportThread creation, Status %x\n", Status);
DfsLogDfsEvent(DFS_ERROR_THREADINIT_FAILED, 0, NULL, Status);
goto Exit;
}
//
// Create our scavenge thread.
//
HANDLE THandle;
THandle = CreateThread (
NULL,
0,
DfsWorkerThread,
0,
0,
&Tid);
if (THandle != NULL)
{
CloseHandle(THandle);
DFS_TRACE_HIGH(REFERRAL_SERVER, "[%!FUNC!- Level %!LEVEL!]Created Scavenge Thread (%d) Tid\n", Tid);
}
else
{
Status = GetLastError();
DFS_TRACE_HIGH(REFERRAL_SERVER, "[%!FUNC!- Level %!LEVEL!]Failed Scavenge Thread creation, Status %x\n", Status);
CloseHandle(DfsServerGlobalData.SiteSupportThreadHandle);
DfsServerGlobalData.SiteSupportThreadHandle = NULL;
goto Exit;
}
Status = DfsInitializeReflectionEngine();
if(Status != ERROR_SUCCESS)
{
DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "[%!FUNC!- Level %!LEVEL!]Initialize Reflection Engine, Status %x\n", Status);
DfsLogDfsEvent(DFS_ERROR_REFLECTIONENGINE_FAILED, 0, NULL, Status);
goto Exit;
}
Exit:
if(Status != ERROR_SUCCESS)
{
DfsServerGlobalData.ServiceState = SERVICE_STOPPED;
}
return Status;
}
DFSSTATUS
DfsServerStop(
ULONG Flags )
{
UNREFERENCED_PARAMETER(Flags);
DFSSTATUS Status = ERROR_SUCCESS;
DfsServerGlobalData.bIsShuttingDown = TRUE;
if(DfsServerGlobalData.ServiceState == SERVICE_RUNNING)
{
DfsServerGlobalData.ServiceState = SERVICE_STOP_PENDING;
if(DfsServerGlobalData.ShutdownHandle)
{
SetEvent(DfsServerGlobalData.ShutdownHandle);
}
Status = DfsTerminateReflectionEngine();
if(DfsServerGlobalData.ShutdownHandle)
{
CloseHandle(DfsServerGlobalData.ShutdownHandle);
DfsServerGlobalData.ShutdownHandle = NULL;
}
DfsServerGlobalData.ServiceState = SERVICE_STOPPED;
}
return Status;
}
//+-------------------------------------------------------------------------
//
// Function: DfsServerLibraryInitialize
//
// Arguments: Flags - the server flags
// DfsName - server name
//
// Returns: Status
// ERROR_SUCCESS on success
// ERROR status code otherwise
//
//
// Description: This performs a trimmed down DfsServerInitialize
// for clients who want to bypass the server and access
// the domain dfs information directly.
//
//--------------------------------------------------------------------------
DFSSTATUS
DfsServerLibraryInitialize(
ULONG Flags )
{
DFSSTATUS Status = ERROR_SUCCESS;
BOOL fCritInit = FALSE;
PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pPrimaryDomainInfo = NULL;
ZeroMemory(&DfsServerGlobalData, sizeof(DfsServerGlobalData));
DfsServerGlobalData.pRegisteredStores = NULL;
DfsServerGlobalData.Flags = Flags;
DfsServerGlobalData.bIsShuttingDown = FALSE;
fCritInit = InitializeCriticalSectionAndSpinCount( &DfsServerGlobalData.DataLock, DFS_CRIT_SPIN_COUNT);
if(!fCritInit)
{
Status = GetLastError();
}
//
// Now register all the stores. This essentially constructs the respective
// store class objects.
//
if (Status == ERROR_SUCCESS) {
Status = DfsRegisterStores();
DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "[%!FUNC!- Level %!LEVEL!]DfsRegisterStores Status %x\n", Status);
}
DfsServerGlobalData.LdapTimeOut = DFS_LDAP_TIMEOUT;
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(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 = NULL;
//
// 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 );
//
// 565500, delete allocation on errors.
//
if (Status != ERROR_SUCCESS)
{
delete [] NewName;
}
if (Status == ERROR_DUP_NAME)
{
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 = 0;
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.
//
//--------------------------------------------------------------------------
DFSSTATUS
DfsHandleNamespaces()
{
ULONG i = 0;
DFSSTATUS Status = ERROR_SUCCESS;
DFSSTATUS RetStatus = ERROR_SUCCESS;
for (i = 0; i < DfsServerGlobalData.NumberOfNamespaces; i++) {
DFSLOG("Calling recognize on %wS\n",
DfsServerGlobalData.HandledNamespace[ i ] );
Status = DfsRecognize( DfsServerGlobalData.HandledNamespace[ i ] );
//
// xxx This error isn't the original error; it's typically
// something like ERROR_NOT_READY currently. We need to change that
// in the future.
//
if (Status != ERROR_SUCCESS)
{
RetStatus = Status;
}
if (DfsIsShuttingDown())
{
break;
}
}
// If we got an error at any point, return that.
return RetStatus;
}
//+-------------------------------------------------------------------------
//
// 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.
//
//--------------------------------------------------------------------------
DFSSTATUS
DfsRecognize(
LPWSTR Name)
{
DfsStore *pStore = NULL;
LPWSTR UseName = NULL;
DFSSTATUS Status = ERROR_SUCCESS;
DFSSTATUS RetStatus = ERROR_SUCCESS;
//
// 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 );
Status = pStore->StoreRecognizer( UseName );
//
// If any of the roots failed to load, typically because
// the DC was unavailable, then we need to make a note of
// that and retry later.
//
if (Status != ERROR_SUCCESS)
{
RetStatus = Status;
}
if (DfsIsShuttingDown())
{
break;
}
}
return RetStatus;
}
//+-------------------------------------------------------------------------
//
// Function: DfsRecognize
//
// Arguments: Namespace
// LogicalShare
//
// Returns: SUCCESS if we managed to create a root folder, ERROR otherwise.
//
// Description: This routine passes the name to each registered store
// by calling the StoreRecognize method. The store will
// decide whether the given root exist on that namespace, and adds
// the discovered root to a list maintained by the store.
//
//--------------------------------------------------------------------------
DFSSTATUS
DfsRecognize(
LPWSTR Name,
PUNICODE_STRING pLogicalShare)
{
DfsStore *pStore = NULL;
DFSSTATUS Status = ERROR_NOT_FOUND;
if (IsEmptyString(Name) || IsEmptyString(pLogicalShare->Buffer))
{
return ERROR_INVALID_PARAMETER;
}
//
// Call the store recognizer of each registered store.
//
for (pStore = DfsServerGlobalData.pRegisteredStores;
pStore != NULL;
pStore = pStore->pNextRegisteredStore) {
DFSLOG("Calling StoreRecognizer (remote) on %wS for store %p\n",
Name, pStore );
Status = pStore->StoreRecognizer( Name, pLogicalShare );
//
// A store has successfully recognized a root for this <name,share>.
// We are done.
//
if (Status == ERROR_SUCCESS)
break;
}
DFS_TRACE_LOW(REFERRAL_SERVER, "StoreRecognizer (remote) Status %x\n", Status);
return Status;
}
VOID
DfsSynchronize()
{
DfsStore *pStore = NULL;
//
// 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();
if (DfsIsShuttingDown())
{
break;
}
}
return NOTHING;
}
//+-------------------------------------------------------------------------
//
// Function: DfsDumpStatistics
//
// Arguments: NONE
//
// Returns: None
//
//--------------------------------------------------------------------------
VOID
DfsDumpStatistics( )
{
DfsStore *pStore = NULL;
//
// Call the store recognizer of each registered store.
//
for (pStore = DfsServerGlobalData.pRegisteredStores;
pStore != NULL;
pStore = pStore->pNextRegisteredStore) {
pStore->DumpStatistics();
if (DfsIsShuttingDown())
{
break;
}
}
return NOTHING;
}
void
DfsinitializeWorkerThreadInfo(void)
{
//
// Iterate through all the stores and 'recognize' their roots.
//
DfsHandleNamespaces();
DfsLogDfsEvent(DFS_INFO_FINISH_BUILDING_NAMESPACE, 0, NULL, 0);
StartPreloadingServerSiteData();
DfsServerGlobalData.IsStartupProcessingDone = TRUE;
DfsLogDfsEvent(DFS_INFO_FINISH_INIT, 0, NULL, 0);
ResumeThread(DfsServerGlobalData.SiteSupportThreadHandle);
CloseHandle(DfsServerGlobalData.SiteSupportThreadHandle);
DfsServerGlobalData.SiteSupportThreadHandle = NULL;
DfsServerGlobalData.ServiceState = SERVICE_RUNNING;
}
void
DfsProcessAgedReferrelList(void)
{
DfsFolderReferralData *pRefData = NULL;
DfsFolderReferralData *pRefList = NULL;
DFS_TRACE_LOW( REFERRAL_SERVER, "[%!FUNC!- Level %!LEVEL!]Worker thread handling all namespaces\n");
DfsHandleNamespaces();
DFS_TRACE_LOW(REFERRAL_SERVER, "[%!FUNC!- Level %!LEVEL!]Worker thread done syncing\n");
DfsDumpStatistics();
//
// now run through the loaded list and pick up aged referrals.
// and unload them.
//
DfsGetAgedReferralList( &pRefList );
while (pRefList != NULL)
{
DfsFolder *pFolder;
pRefData = pRefList;
if (pRefData->pNextLoaded == pRefData)
{
pRefList = NULL;
}
else
{
pRefList = pRefData->pNextLoaded;
pRefData->pNextLoaded->pPrevLoaded = pRefData->pPrevLoaded;
pRefData->pPrevLoaded->pNextLoaded = pRefData->pNextLoaded;
}
pFolder = pRefData->GetOwningFolder();
if (pFolder != NULL)
{
pFolder->RemoveReferralData( pRefData );
}
pRefData->ReleaseReference();
} // while
}
//+-------------------------------------------------------------------------
//
// 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;
#define DFS_NAMESPACE_RETRY_STARTING_INTERVAL (15 * 1000);
#define DFS_NAMESPACE_MAX_RETRIES 5
DWORD
DfsWorkerThread(LPVOID TData)
{
DfsFolderReferralData *pRefData = NULL, *pRefList = NULL;
HRESULT hr = S_OK;
SYSTEMTIME StartupSystemTime;
FILETIME ReparseScavengeTime;
BOOLEAN DoReparseScavenge = TRUE;
DFSSTATUS RecognizeStatus = ERROR_SUCCESS;
DWORD RetryScavengeTimeLeft = 0;
ULONG InitialRetry = DFS_NAMESPACE_MAX_RETRIES;
static LoopCnt = 0;
ScavengeTime = DFS_NAMESPACE_RETRY_STARTING_INTERVAL; // 15 seconds
UNREFERENCED_PARAMETER(TData);
hr = CoInitializeEx(NULL,COINIT_MULTITHREADED| COINIT_DISABLE_OLE1DDE);
//
// As long as reparse points are created after this time stamp, we are fine.
//
GetSystemTime( &StartupSystemTime );
if (!SystemTimeToFileTime( &StartupSystemTime, &ReparseScavengeTime ))
{
DoReparseScavenge = FALSE;
}
//
// Iterate through all the stores and 'recognize' their roots.
// If any of them failed to load we retry a set number of times below.
//
RecognizeStatus = DfsHandleNamespaces();
DfsLogDfsEvent(DFS_INFO_FINISH_BUILDING_NAMESPACE, 0, NULL, 0);
StartPreloadingServerSiteData();
DfsServerGlobalData.IsStartupProcessingDone = TRUE;
DfsLogDfsEvent(DFS_INFO_FINISH_INIT, 0, NULL, 0);
ResumeThread(DfsServerGlobalData.SiteSupportThreadHandle);
CloseHandle(DfsServerGlobalData.SiteSupportThreadHandle);
DfsServerGlobalData.SiteSupportThreadHandle = NULL;
DfsServerGlobalData.ServiceState = SERVICE_RUNNING;
// Retry failed namespaces.
while ( (RecognizeStatus != ERROR_SUCCESS) &&
(InitialRetry-- > 0) )
{
WaitForSingleObject(DfsServerGlobalData.ShutdownHandle, ScavengeTime);
if (DfsIsShuttingDown())
{
goto Exit;
}
DFS_TRACE_HIGH( REFERRAL_SERVER, "[%!FUNC!- Level %!LEVEL!]Worker thread retrying failed namespaces after %d secs\n",
ScavengeTime/1000);
RecognizeStatus = DfsHandleNamespaces();
DFS_TRACE_HIGH(REFERRAL_SERVER, "[%!FUNC!- Level %!LEVEL!]Worker thread done retrying, Status 0x%x\n", RecognizeStatus);
ScavengeTime *= 2;
}
// Revert to the 'normal' sleep time (~1hr)
ScavengeTime = SCAVENGE_TIME;
while (TRUE) {
DFS_TRACE_LOW( REFERRAL_SERVER, "[%!FUNC!- Level %!LEVEL!]Worker thread sleeping for %d\n", ScavengeTime);
WaitForSingleObject(DfsServerGlobalData.ShutdownHandle, ScavengeTime);
if (DfsIsShuttingDown())
{
goto Exit;
}
LoopCnt++;
// DfsDev: need to define a better mechanism as to how often
// this gets to run.
//
DFS_TRACE_LOW( REFERRAL_SERVER, "[%!FUNC!- Level %!LEVEL!]Worker thread handling all namespaces\n");
RecognizeStatus = DfsHandleNamespaces();
DFS_TRACE_LOW(REFERRAL_SERVER, "[%!FUNC!- Level %!LEVEL!]Worker thread done syncing, status 0x%x\n", RecognizeStatus);
DfsDumpStatistics();
//
// now run through the loaded list and pick up aged referrals.
// and unload them.
//
DfsGetAgedReferralList( &pRefList );
while (pRefList != NULL)
{
DfsFolder *pFolder;
pRefData = pRefList;
if (pRefData->pNextLoaded == pRefData)
{
pRefList = NULL;
}
else
{
pRefList = pRefData->pNextLoaded;
pRefData->pNextLoaded->pPrevLoaded = pRefData->pPrevLoaded;
pRefData->pPrevLoaded->pNextLoaded = pRefData->pNextLoaded;
}
pFolder = pRefData->GetOwningFolder();
if (pFolder != NULL)
{
pFolder->RemoveReferralData( pRefData );
}
pRefData->ReleaseReference();
} // while
//
// If we haven't cleaned up orphaned reparse points, do that now.
// Note that this doesn't run until SCAVEGE_TIME seconds after
// the service has started.
//
if (DoReparseScavenge)
{
// We have no choice but to ignore errors
(VOID)DfsRemoveOrphanedReparsePoints( ReparseScavengeTime );
// This gets to run only once, irrespective of any errors.
DoReparseScavenge = FALSE;
}
}
Exit:
CoUninitialize();
return 0;
}
DWORD
DfsSiteSupportThread(LPVOID TData)
{
DWORD dw = 0;
UNREFERENCED_PARAMETER(TData);
while (TRUE)
{
DFS_TRACE_LOW( REFERRAL_SERVER, "[%!FUNC!- Level %!LEVEL!]DfsSiteSupportThread sleeping for %d\n",
DfsServerGlobalData.SiteSupportThreadInterval);
dw = WaitForSingleObject(DfsServerGlobalData.ShutdownHandle,
DfsServerGlobalData.SiteSupportThreadInterval);
if(WAIT_TIMEOUT == dw)
{
DfsServerGlobalData.pSiteNameSupport->InvalidateAgedSites();
DfsServerGlobalData.pClientSiteSupport->RefreshSiteData();
StartPreloadingServerSiteData();
}
if (DfsIsShuttingDown())
{
break;
}
}
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: DfsGetAgedReferralList
//
// Arguments: ppReferralData
//
// Returns: Nothing
//
// Description: This routine removes the list and hands it back to the
// caller. It sets the list as empty.
// The caller is responsible for freeing up the list
//
//--------------------------------------------------------------------------
VOID
DfsGetAgedReferralList(
DfsFolderReferralData **ppReferralData )
{
//
// this needs to be optimized to return a subset or LRU entries.
//
ACQUIRE_LOADED_LIST_LOCK();
*ppReferralData = DfsServerGlobalData.LoadedList;
DfsServerGlobalData.LoadedList = NULL;
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,
BOOLEAN * CacheHit,
BOOLEAN SyncThread )
{
return DfsServerGlobalData.pServerSiteSupport->GetServerSiteInfo(pServer, ppInfo, CacheHit, SyncThread );
}
//+-------------------------------------------------------------------------
//
// 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.pServerSiteSupport->ReleaseServerSiteInfo(pInfo);
}
//+-------------------------------------------------------------------------
//
// Function: DfsGetDefaultSite
//
// Arguments: Nothing
//
// Returns: DfsSite
//
// Description: This routine returns a referenced pointer to the default DfsSite.
// The site name of this site is empty. Once done, caller is supposed to call
// ReleaseReference() on the DfsSite returned here.
//--------------------------------------------------------------------------
DfsSite *
DfsGetDefaultSite( VOID )
{
DfsServerGlobalData.pDefaultSite->AcquireReference();
return DfsServerGlobalData.pDefaultSite;
}
//+-------------------------------------------------------------------------
//
// 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 NameBufferCchLength;
LPWSTR NameBuffer;
DFSSTATUS Status = ERROR_SUCCESS ;
NameBufferCchLength = COMPUTER_NAME_BUFFER_SIZE;
NameBuffer = new WCHAR [ NameBufferCchLength ];
if (NameBuffer != NULL)
{
INITIALIZE_COMPUTER_INFO( ComputerNameNetBIOS, NameBuffer, NameBufferCchLength, Status );
INITIALIZE_COMPUTER_INFO( ComputerNameDnsFullyQualified, NameBuffer, NameBufferCchLength, Status );
INITIALIZE_COMPUTER_INFO( ComputerNameDnsDomain, NameBuffer, NameBufferCchLength, 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 (DfsServerGlobalData.DfsDnsConfig == 0)
{
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 = ERROR_SUCCESS;
LPWSTR UseName = NULL;
if (DfsServerGlobalData.DfsDnsConfig == 0)
{
if (!IsEmptyString(DfsServerGlobalData.DomainNameFlat.Buffer))
{
UseName = DfsServerGlobalData.DomainNameFlat.Buffer;
}
else if (!IsEmptyString(DfsServerGlobalData.DomainNameDns.Buffer))
{
UseName = DfsServerGlobalData.DomainNameDns.Buffer;
}
else if (!IsEmptyString(DfsServerGlobalData.DfsMachineInfo.StaticComputerNameDnsDomain))
{
UseName = DfsServerGlobalData.DfsMachineInfo.StaticComputerNameDnsDomain;
}
else
{
Status = ERROR_INVALID_PARAMETER;
}
}
else
{
if (!IsEmptyString(DfsServerGlobalData.DomainNameDns.Buffer))
{
UseName = DfsServerGlobalData.DomainNameDns.Buffer;
}
else if (!IsEmptyString(DfsServerGlobalData.DfsMachineInfo.StaticComputerNameDnsDomain))
{
UseName = DfsServerGlobalData.DfsMachineInfo.StaticComputerNameDnsDomain;
}
else if (!IsEmptyString(DfsServerGlobalData.DomainNameFlat.Buffer))
{
UseName = DfsServerGlobalData.DomainNameFlat.Buffer;
}
else
{
Status = ERROR_INVALID_PARAMETER;
}
}
if (Status == ERROR_SUCCESS)
{
Status = DfsCreateUnicodeStringFromString( pName,
UseName );
}
return Status;
}
DFSSTATUS
DfsGetDnsDomainName(
PUNICODE_STRING pName)
{
DFSSTATUS Status = ERROR_SUCCESS;
LPWSTR UseName = NULL;
if (!IsEmptyString(DfsServerGlobalData.DomainNameDns.Buffer))
{
UseName = DfsServerGlobalData.DomainNameDns.Buffer;
}
else
{
Status = ERROR_NOT_FOUND;
}
if (Status == ERROR_SUCCESS)
{
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 = STATUS_SUCCESS;
PVOID pData = NULL;
BOOLEAN SubStringMatch = FALSE;
UNICODE_STRING RemainingName;
NtStatus = DfsPrefixTableAcquireWriteLock( DfsServerGlobalData.pDirectoryPrefixTable );
if ( NtStatus == STATUS_SUCCESS )
{
NtStatus = DfsFindUnicodePrefixLocked( DfsServerGlobalData.pDirectoryPrefixTable,
pDirectoryName,
&RemainingName,
&pData,
&SubStringMatch );
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 = STATUS_SUCCESS;
PVOID pData = NULL;
BOOLEAN SubStringMatch = FALSE;
UNICODE_STRING RemainingName;
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 = ERROR_SUCCESS;
EnterCriticalSection(pLock);
return Status;
}
DFSSTATUS
DfsAcquireReadLock(
PCRITICAL_SECTION pLock)
{
DFSSTATUS Status = ERROR_SUCCESS;
EnterCriticalSection(pLock);
return Status;
}
VOID
DfsSetGlobalDomainInfo(
DfsDomainInformation *pDomainInfo)
{
DFSSTATUS Status;
DfsDomainInformation *pOldInfo = NULL;
Status = DfsAcquireGlobalDataLock();
if (Status == ERROR_SUCCESS)
{
pDomainInfo->AcquireReference();
pOldInfo = DfsServerGlobalData.pDomainInfo;
DfsServerGlobalData.pDomainInfo = pDomainInfo;
DfsReleaseGlobalDataLock();
}
if (pOldInfo != NULL)
{
pOldInfo->ReleaseReference();
}
return NOTHING;
}
DFSSTATUS
DfsAcquireDomainInfo (
DfsDomainInformation **ppDomainInfo )
{
DFSSTATUS Status = ERROR_SUCCESS;
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)
{
DFSSTATUS Status = ERROR_SUCCESS;
UNICODE_STRING DomainNameFlat;
Status = DfsRtlInitUnicodeStringEx( &DomainNameFlat, DomainNameFlatString);
if(Status == ERROR_SUCCESS)
{
Status = DfsCreateUnicodeString( &DfsServerGlobalData.DomainNameFlat,
&DomainNameFlat );
}
return Status;
}
DFSSTATUS
DfsSetDomainNameDns( LPWSTR DomainNameDnsString )
{
DFSSTATUS Status = ERROR_SUCCESS;
UNICODE_STRING DomainNameDns;
Status = DfsRtlInitUnicodeStringEx( &DomainNameDns, DomainNameDnsString);
if(Status == ERROR_SUCCESS)
{
Status = DfsCreateUnicodeString( &DfsServerGlobalData.DomainNameDns,
&DomainNameDns);
}
return Status;
}
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;
}
//*************************************************************
//
// IsNullGUID()
//
// Purpose: Determines if the passed in GUID is all zeros
//
// Parameters: pguid GUID to compare
//
// Return: TRUE if the GUID is all zeros
// FALSE if not
//
//*************************************************************
BOOL IsNullGUID (GUID *pguid)
{
return ( (pguid->Data1 == 0) &&
(pguid->Data2 == 0) &&
(pguid->Data3 == 0) &&
(pguid->Data4[0] == 0) &&
(pguid->Data4[1] == 0) &&
(pguid->Data4[2] == 0) &&
(pguid->Data4[3] == 0) &&
(pguid->Data4[4] == 0) &&
(pguid->Data4[5] == 0) &&
(pguid->Data4[6] == 0) &&
(pguid->Data4[7] == 0) );
}
BOOLEAN
DfsGetGlobalRegistrySettings(void)
{
BOOLEAN fRet = TRUE;
HKEY hkeyDfs = NULL;
HKEY hkeyDfs2 = NULL;
DWORD dwErr = 0;
DWORD dwDisp = 0;
dwErr = RegCreateKeyEx(HKEY_LOCAL_MACHINE, DfsSvcPath,
NULL,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_READ|KEY_WRITE, // Write = Create if
NULL, &hkeyDfs, &dwDisp);
if (dwErr == ERROR_SUCCESS)
{
//
//support the old format of specifying the time interval to refresh.
//
DfsServerGlobalData.CacheFlushInterval = DfsReadRegistryDword(hkeyDfs,
DfsWorkerThreadIntervalName,
CACHE_FLUSH_INTERVAL/1000);
dwErr = RegCreateKeyEx(HKEY_LOCAL_MACHINE, DfsParamPath, NULL, NULL,
REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, &hkeyDfs2, &dwDisp);
if (dwErr == ERROR_SUCCESS)
{
DfsServerGlobalData.SiteSupportRefreshInterval = DfsReadRegistryDword(hkeyDfs2, DfsSiteSupportRefreshIntervalName, SITE_REFRESH_INTERVAL/1000);
//
// domain name refresh interval defaults to same as site refresh: 12 hours
//
DfsServerGlobalData.DomainNameRefreshInterval = DfsReadRegistryDword(hkeyDfs2, DfsDomainNameRefreshInterval, SITE_REFRESH_INTERVAL/1000);
DfsServerGlobalData.SiteIpCacheTrimValue = DfsReadRegistryDword(hkeyDfs2, DfsSiteIpCacheTrimValueName, SITE_IPCACHE_TRIM_VALUE);
DfsServerGlobalData.AllowedErrors = DfsReadRegistryDword(hkeyDfs2, DfsAllowableErrorsValueName, DFS_MAX_ROOT_ERRORS);
DfsServerGlobalData.LdapTimeOut = DfsReadRegistryDword(hkeyDfs2, DfsLdapTimeoutValueName, DFS_LDAP_TIMEOUT);
DfsServerGlobalData.NumClientSiteEntriesAllowed = DfsReadRegistryDword(hkeyDfs2, DfsMaxClientSiteValueName, DFS_INITIAL_CLIENTS_SITES);
DfsServerGlobalData.QuerySiteCostTimeoutInSeconds = DfsReadRegistryDword(hkeyDfs2, DfsQuerySiteCostTimeoutName, DFS_QUERY_SITE_COST_TIMEOUT);
DfsServerGlobalData.RootReferralRefreshInterval = DfsReadRegistryDword(hkeyDfs2, DFS_REG_ROOT_REFERRAL_TIMEOUT_NAME, ROOTREF_REFRESH_INTERVAL/1000);
if (DfsReadRegistryDword(hkeyDfs2, DfsSiteCostedReferralsValueName, 0) != 0)
{
DfsServerGlobalData.Flags |= DFS_SITE_COSTED_REFERRALS;
}
if (DfsReadRegistryDword(hkeyDfs2, DfsInsiteReferralsValueName, 0) != 0)
{
DfsServerGlobalData.Flags |= DFS_INSITE_REFERRALS;
}
//
// if we are possibly in a NT4 domain, check if we need to disable
// siteawareness.
//
{
LSA_OBJECT_ATTRIBUTES ObjectAttributes;
NTSTATUS status = 0;
LSA_HANDLE hPolicy;
BOOLEAN CheckRegistry = TRUE;
DfsServerGlobalData.DisableSiteAwareness = FALSE;
//attempt to open the policy.
ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));//object attributes are reserved, so initalize to zeroes.
status = LsaOpenPolicy( NULL,
&ObjectAttributes,
POLICY_VIEW_LOCAL_INFORMATION,
&hPolicy); //recieves the policy handle
if (NT_SUCCESS(status))
{
//ask for audit event policy information
PPOLICY_DNS_DOMAIN_INFO info;
status = LsaQueryInformationPolicy(hPolicy,
PolicyDnsDomainInformation,
(PVOID *)&info);
if (NT_SUCCESS(status))
{
if (!IsNullGUID(&info->DomainGuid))
{
CheckRegistry = FALSE;
}
LsaFreeMemory((PVOID) info); //free policy info structure
}
LsaClose(hPolicy); //Freeing the policy object handle
}
if (CheckRegistry)
{
DWORD DisableSiteAwareness = 0;
DisableSiteAwareness =
DfsReadRegistryDword( hkeyDfs2,
DFS_DISABLE_SITE_AWARENESS,
DisableSiteAwareness );
DfsServerGlobalData.DisableSiteAwareness = (DisableSiteAwareness == 0) ? FALSE : TRUE;
}
}
RegCloseKey(hkeyDfs2);
}
RegCloseKey(hkeyDfs);
}
DfsServerGlobalData.CacheFlushInterval *= 1000;
if(DfsServerGlobalData.CacheFlushInterval < CACHE_FLUSH_MIN_INTERVAL)
{
DfsServerGlobalData.CacheFlushInterval = CACHE_FLUSH_MIN_INTERVAL;
DfsServerGlobalData.RetryFailedReferralLoadInterval = DfsServerGlobalData.CacheFlushInterval / 3;
}
else
{
DfsServerGlobalData.RetryFailedReferralLoadInterval = DfsServerGlobalData.CacheFlushInterval /4;
}
DfsServerGlobalData.SiteSupportRefreshInterval *= 1000;
if(DfsServerGlobalData.SiteSupportRefreshInterval == 0)
{
DfsServerGlobalData.SiteSupportRefreshInterval = SITE_REFRESH_INTERVAL;
}
if(DfsServerGlobalData.SiteSupportRefreshInterval < MIN_SITE_REFRESH_INTERVAL)
{
DfsServerGlobalData.SiteSupportRefreshInterval = MIN_SITE_REFRESH_INTERVAL;
}
if(DfsServerGlobalData.DomainNameRefreshInterval < MIN_DOMAIN_REFRESH_INTERVAL)
{
DfsServerGlobalData.DomainNameRefreshInterval = MIN_DOMAIN_REFRESH_INTERVAL;
}
if(DfsServerGlobalData.NumClientSiteEntriesAllowed < DFS_MINIMUM_CLIENTS_SITES)
{
DfsServerGlobalData.NumClientSiteEntriesAllowed = DFS_MINIMUM_CLIENTS_SITES;
}
if (DfsServerGlobalData.QuerySiteCostTimeoutInSeconds < DFS_MIN_QUERY_SITE_COST_TIMEOUT)
{
DfsServerGlobalData.QuerySiteCostTimeoutInSeconds = DFS_MIN_QUERY_SITE_COST_TIMEOUT;
}
else if (DfsServerGlobalData.QuerySiteCostTimeoutInSeconds > DFS_MAX_QUERY_SITE_COST_TIMEOUT)
{
DfsServerGlobalData.QuerySiteCostTimeoutInSeconds = DFS_MAX_QUERY_SITE_COST_TIMEOUT;
}
DfsServerGlobalData.RootReferralRefreshInterval *= 1000;
if(DfsServerGlobalData.RootReferralRefreshInterval < ROOTREF_REFRESH_INTERVAL)
{
DfsServerGlobalData.RootReferralRefreshInterval = ROOTREF_REFRESH_INTERVAL;
}
DfsServerGlobalData.SiteSupportThreadInterval = DfsServerGlobalData.SiteSupportRefreshInterval - SITE_THREAD_INTERVAL_DIFF;
DfsServerGlobalData.FirstContact = DFS_DS_ACTIVE;
DFS_TRACE_LOW( REFERRAL_SERVER, "[%!FUNC!]Read regkey DfsServerGlobalData.SiteSupportRefreshInterval %d\n", DfsServerGlobalData.SiteSupportRefreshInterval);
DFS_TRACE_LOW( REFERRAL_SERVER, "[%!FUNC!]Read regkey DfsServerGlobalData.CacheFlushInterval %d\n", DfsServerGlobalData.CacheFlushInterval);
DFS_TRACE_LOW( REFERRAL_SERVER, "[%!FUNC!]Read regkey DfsServerGlobalData.SiteIpCacheTrimValue %d\n", DfsServerGlobalData.SiteIpCacheTrimValue);
DFS_TRACE_LOW( REFERRAL_SERVER, "[%!FUNC!]Read regkey DfsServerGlobalData.AllowedErrors %d\n", DfsServerGlobalData.AllowedErrors);
DFS_TRACE_LOW( REFERRAL_SERVER, "[%!FUNC!]Read regkey DfsServerGlobalData.LdapTimeOut %d\n", DfsServerGlobalData.LdapTimeOut);
DFS_TRACE_LOW( REFERRAL_SERVER, "[%!FUNC!]Read regkey DfsServerGlobalData.NumClientSiteEntriesAllowed %d\n", DfsServerGlobalData.NumClientSiteEntriesAllowed);
return fRet;
}
BOOLEAN
DfsGetStaticGlobalRegistrySettings(void)
{
BOOLEAN fRet = TRUE;
HKEY hkeyDfs = NULL;
HKEY hkeyDfs2 = NULL;
DWORD dwErr = 0;
DWORD dwDisp = 0;
dwErr = RegCreateKeyEx(HKEY_LOCAL_MACHINE, DfsSvcPath,
NULL,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_READ|KEY_WRITE, // Write = Create if
NULL, &hkeyDfs, &dwDisp);
if (dwErr == ERROR_SUCCESS)
{
DfsServerGlobalData.DfsDnsConfig = (DWORD) !!DfsReadRegistryDword(hkeyDfs,
DfsDnsConfigValue,
0 );
dwErr = RegCreateKeyEx(HKEY_LOCAL_MACHINE, DfsParamPath, NULL, NULL,
REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, &hkeyDfs2, &dwDisp);
if (dwErr == ERROR_SUCCESS)
{
DfsServerGlobalData.NumWorkerThreads = DfsReadRegistryDword(hkeyDfs2, DFS_REG_WORKER_THREAD_VALUE, DFS_DEFAULT_WORKER_THREADS);
RegCloseKey(hkeyDfs2);
}
if(DfsServerGlobalData.NumWorkerThreads < DFS_MIN_WORKER_THREADS)
{
DfsServerGlobalData.NumWorkerThreads = DFS_MIN_WORKER_THREADS;
}
else if (DfsServerGlobalData.NumWorkerThreads > DFS_MAX_WORKER_THREADS)
{
DfsServerGlobalData.NumWorkerThreads = DFS_MAX_WORKER_THREADS;
}
RegCloseKey(hkeyDfs);
}
return fRet;
}
#define DFS_PDC_CACHE_TIME_INTERVAL 60 * 60 * 1000 // 60 minutes.
DFSSTATUS
DfsGetBlobPDCName(
DfsString **ppPDCName,
ULONG Flags,
LPWSTR DomainName )
{
PDOMAIN_CONTROLLER_INFO pDomainControllerInfo = NULL;
DFSSTATUS Status = ERROR_SUCCESS;
DFSSTATUS LockStatus = ERROR_SUCCESS;
ULONG CurrentTimeStamp = 0;
ULONG TimeDiff = 0;
BOOLEAN NewDcAttempted = FALSE;
DfsString NewDC;
*ppPDCName = NULL;
DfsGetTimeStamp(&CurrentTimeStamp);
TimeDiff = CurrentTimeStamp - DfsServerGlobalData.PDCTimeStamp;
if ((Flags & DFS_FORCE_DC_QUERY) ||
(TimeDiff > DFS_PDC_CACHE_TIME_INTERVAL) ||
(DfsServerGlobalData.PDCTimeStamp == 0))
{
NewDcAttempted = TRUE;
Status = DsGetDcName( NULL, //computer name
DomainName, // domain name
NULL, // domain guid
NULL, // site name
DS_DIRECTORY_SERVICE_REQUIRED |
DS_PDC_REQUIRED |
DS_FORCE_REDISCOVERY,
&pDomainControllerInfo );
DFS_TRACE_LOW( REFERRAL_SERVER, "Got New PDC, Status %x\n", Status);
if (Status == ERROR_SUCCESS)
{
Status = NewDC.CreateString(&pDomainControllerInfo->DomainControllerName[2] );
NetApiBufferFree(pDomainControllerInfo);
}
}
else
{
Status = DfsServerGlobalData.PDCStatus;
}
LockStatus = DfsAcquireGlobalDataLock();
if (LockStatus != ERROR_SUCCESS) {
return LockStatus;
}
if (NewDcAttempted == TRUE)
{
if (Status == ERROR_SUCCESS)
{
Status = DfsServerGlobalData.PDCName.CreateString(&NewDC);
}
if (Status == ERROR_SUCCESS)
{
DfsServerGlobalData.PDCTimeStamp = CurrentTimeStamp;
}
DfsServerGlobalData.PDCStatus = Status;
}
if ((Status == ERROR_SUCCESS) &&
(ppPDCName != NULL))
{
DfsString *pReturnDcName;
pReturnDcName = new DfsString;
if (pReturnDcName == NULL)
{
Status = ERROR_NOT_ENOUGH_MEMORY;
}
else
{
Status = pReturnDcName->CreateString(&DfsServerGlobalData.PDCName );
if (Status == ERROR_SUCCESS)
{
*ppPDCName = pReturnDcName;
}
else
{
delete pReturnDcName;
}
}
}
DfsReleaseGlobalDataLock();
if (*ppPDCName != NULL) {
DFS_TRACE_LOW( REFERRAL_SERVER, "[%!FUNC!- Level %!LEVEL!]Returning PDC: %ws, Status %x\n",
(*ppPDCName)->GetString(), Status);
}
return Status;
}
DFSSTATUS
DfsSetBlobPDCName(
LPWSTR DCName,
DfsString **ppPDCName)
{
DFSSTATUS Status = ERROR_SUCCESS;
DFSSTATUS LockStatus = ERROR_SUCCESS;
DfsString NewDC;
ULONG CurrentTimeStamp = 0;
DfsGetTimeStamp(&CurrentTimeStamp);
*ppPDCName = NULL;
Status = NewDC.CreateString(DCName);
if (Status != ERROR_SUCCESS)
{
return Status;
}
LockStatus = DfsAcquireGlobalDataLock();
if (LockStatus != ERROR_SUCCESS) {
return LockStatus;
}
Status = DfsServerGlobalData.PDCName.CreateString(&NewDC);
if (Status == ERROR_SUCCESS)
{
DfsServerGlobalData.PDCTimeStamp = CurrentTimeStamp;
}
DfsServerGlobalData.PDCStatus = Status;
if ((Status == ERROR_SUCCESS) &&
(ppPDCName != NULL))
{
DfsString *pReturnDcName;
pReturnDcName = new DfsString;
if (pReturnDcName == NULL)
{
Status = ERROR_NOT_ENOUGH_MEMORY;
}
else
{
Status = pReturnDcName->CreateString(&DfsServerGlobalData.PDCName );
if (Status == ERROR_SUCCESS)
{
*ppPDCName = pReturnDcName;
}
else
{
delete pReturnDcName;
}
}
}
DfsReleaseGlobalDataLock();
if (*ppPDCName != NULL) {
DFS_TRACE_LOW( REFERRAL_SERVER, "[%!FUNC!- Level %!LEVEL!]Returning PDC: %ws, Status %x\n",
(*ppPDCName)->GetString(), Status);
}
return Status;
}
VOID
DfsReleaseBlobPDCName(
DfsString *pDCName )
{
if (pDCName != NULL)
{
delete pDCName;
}
}
BOOLEAN
DfsIsTargetCurrentMachine (
PUNICODE_STRING pServer )
{
UNICODE_STRING MachineName;
DFSSTATUS Status = ERROR_SUCCESS;
BOOLEAN ReturnValue = FALSE;
Status = DfsGetMachineName(&MachineName);
if (Status == ERROR_SUCCESS)
{
if (RtlCompareUnicodeString( pServer, &MachineName, TRUE) == 0)
{
ReturnValue = TRUE;
}
DfsFreeUnicodeString( &MachineName );
}
return ReturnValue;
}
LPWSTR
DfsGetDfsAdNameContextString()
{
if (DfsServerGlobalData.DfsAdNameContext.Buffer == NULL)
{
//
// ignore return status: we should log it.
//
DFSSTATUS DummyStatus;
DummyStatus = DfsGenerateDfsAdNameContext(&DfsServerGlobalData.DfsAdNameContext);
}
return DfsServerGlobalData.DfsAdNameContext.Buffer;
}
LPWSTR
DfsGetDfsAdNameContextStringForDomain(LPWSTR UseDC)
{
extern DFSSTATUS DfsGenerateDfsAdNameContextForDomain(PUNICODE_STRING pString,LPWSTR DCName );
if (DfsServerGlobalData.DfsAdNameContext.Buffer != NULL)
{
DfsFreeUnicodeString(&DfsServerGlobalData.DfsAdNameContext);
RtlInitUnicodeString(&DfsServerGlobalData.DfsAdNameContext, NULL);
}
//
// ignore return status: we should log it.
//
DFSSTATUS DummyStatus;
DummyStatus = DfsGenerateDfsAdNameContextForDomain(&DfsServerGlobalData.DfsAdNameContext, UseDC);
return DfsServerGlobalData.DfsAdNameContext.Buffer;
}
extern SECURITY_DESCRIPTOR AdminSecurityDesc;
//+----------------------------------------------------------------------------
//
// Function: InitializeSecurity
//
// Synopsis: Initializes data needed to check the access rights of callers
// of the NetDfs APIs
//
// Arguments: None
//
// Returns: TRUE if successful, FALSE otherwise.
//
//-----------------------------------------------------------------------------
BOOLEAN
DfsInitializeSecurity()
{
static PSID AdminSid;
static PACL AdminAcl;
NTSTATUS status;
ULONG cbAcl;
BOOLEAN InitDone = FALSE;
SID_IDENTIFIER_AUTHORITY ntAuthority = SECURITY_NT_AUTHORITY;
status = RtlAllocateAndInitializeSid(
&ntAuthority,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0,0,0,0,0,0,
&AdminSid);
if (!NT_SUCCESS(status))
return( FALSE );
cbAcl = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(AdminSid);
do {
AdminAcl = (PACL) new BYTE[ cbAcl ];
if (AdminAcl == NULL)
break;
if (!InitializeAcl(AdminAcl, cbAcl, ACL_REVISION))
break;
if (!AddAccessAllowedAce(AdminAcl, ACL_REVISION, STANDARD_RIGHTS_WRITE, AdminSid))
break;
if (!InitializeSecurityDescriptor(&AdminSecurityDesc, SECURITY_DESCRIPTOR_REVISION))
break;
if (!SetSecurityDescriptorOwner(&AdminSecurityDesc, AdminSid, FALSE))
break;
if (!SetSecurityDescriptorGroup(&AdminSecurityDesc, AdminSid, FALSE))
break;
if (!SetSecurityDescriptorDacl(&AdminSecurityDesc, TRUE, AdminAcl, FALSE))
break;
InitDone = TRUE;
} while (FALSE);
if (InitDone == FALSE && AdminAcl != NULL)
{
delete [] AdminAcl;
AdminAcl = NULL;
}
return InitDone;
}
DFSSTATUS
AccessImpersonateCheckRpcClient(void)
{
DFSSTATUS dwErr = 0;
dwErr = AccessImpersonateCheckRpcClientEx(&AdminSecurityDesc,
&AdminGenericMapping,
STANDARD_RIGHTS_WRITE);
return dwErr;
}
VOID
StartPreloadingServerSiteData(void)
{
DfsStore *pStore = NULL;
for (pStore = DfsServerGlobalData.pRegisteredStores; pStore != NULL;
pStore = pStore->pNextRegisteredStore)
{
pStore->LoadServerSiteDataPerRoot();
if (DfsIsShuttingDown())
{
break;
}
}
}
DFSSTATUS
DfsGetCompatRootFolder(
PUNICODE_STRING pName,
DfsRootFolder **ppNewRoot )
{
DfsADBlobStore *pStore = NULL;
DFSSTATUS Status = ERROR_SUCCESS;
Status = DfsGetADBlobStore(&pStore );
if (Status == ERROR_SUCCESS)
{
Status = pStore->GetCompatRootFolder( pName,
ppNewRoot );
pStore->ReleaseReference();
}
return Status;
}
//+----------------------------------------------------------------------------
//
// Function: DfsCacheInsertADRootReferral
//
// Synopsis: Insert a ReferralData structure into our list.
//
// Returns: Status.
//
//-----------------------------------------------------------------------------
typedef struct _DFS_ROOTREF_INFORMATION
{
DfsFolderReferralData * pReferralData;
GUID RootGuid;
}DFS_ROOTREF_INFORMATION, *PDFS_ROOTREF_INFORMATION;
DFSSTATUS
DfsCacheInsertADRootReferral(
PUNICODE_STRING pRootName,
PDFS_ROOTREF_INFORMATION pRefInfo )
{
DFSSTATUS Status = ERROR_SUCCESS;
NTSTATUS NtStatus = STATUS_SUCCESS;
PVOID pData = NULL;
BOOLEAN SubStringMatch = FALSE;
UNICODE_STRING RemainingName;
pRefInfo->pReferralData->AcquireReference();
NtStatus = DfsPrefixTableAcquireWriteLock( DfsServerGlobalData.pRootReferralTable );
if ( NtStatus == STATUS_SUCCESS )
{
NtStatus = DfsFindUnicodePrefixLocked( DfsServerGlobalData.pRootReferralTable,
pRootName,
&RemainingName,
&pData,
&SubStringMatch );
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.pRootReferralTable,
pRootName,
(PVOID)pRefInfo );
}
DfsPrefixTableReleaseLock( DfsServerGlobalData.pRootReferralTable );
}
if(NtStatus != STATUS_SUCCESS)
{
pRefInfo->pReferralData->ReleaseReference();
Status = RtlNtStatusToDosError(NtStatus);
}
return Status;
}
DFSSTATUS
DfsCacheRemoveADRootReferral(
PUNICODE_STRING pRootName,
PDFS_ROOTREF_INFORMATION pRefInfo )
{
DFSSTATUS Status = ERROR_SUCCESS;
NTSTATUS NtStatus = STATUS_SUCCESS;
PVOID pData = NULL;
BOOLEAN SubStringMatch = FALSE;
UNICODE_STRING RemainingName;
NtStatus = DfsPrefixTableAcquireWriteLock( DfsServerGlobalData.pRootReferralTable );
if ( NtStatus == STATUS_SUCCESS )
{
NtStatus = DfsFindUnicodePrefixLocked( DfsServerGlobalData.pRootReferralTable,
pRootName,
&RemainingName,
&pData,
&SubStringMatch );
//
// if we found a perfect match, we can remove this
// from the table.
//
if ( (NtStatus == STATUS_SUCCESS) &&
(RemainingName.Length == 0) )
{
if ((pRefInfo == NULL) || ((PVOID)pRefInfo == pData))
{
pRefInfo = (PDFS_ROOTREF_INFORMATION)pData;
NtStatus = DfsRemoveFromPrefixTableLocked( DfsServerGlobalData.pRootReferralTable,
pRootName,
(PVOID)pData );
}
else
{
NtStatus = STATUS_OBJECT_TYPE_MISMATCH;
}
}
else
{
NtStatus = STATUS_OBJECT_NAME_NOT_FOUND;
}
DfsPrefixTableReleaseLock( DfsServerGlobalData.pRootReferralTable );
}
if (NtStatus == STATUS_SUCCESS)
{
pRefInfo->pReferralData->ReleaseReference();
delete [] pRefInfo;
}
else
{
Status = RtlNtStatusToDosError(NtStatus);
}
return Status;
}
DFSSTATUS
DfsGetADRootReferralInformation(
PUNICODE_STRING pRootName,
PDFS_ROOTREF_INFORMATION * pRefInformation,
GUID *pNewGuid)
{
DFSSTATUS Status = ERROR_SUCCESS;
DfsFolderReferralData *pReferralData = NULL;
BOOLEAN CacheHit = TRUE;
PDFS_ROOTREF_INFORMATION pRefInfo = NULL;
UNICODE_STRING RemainingName;
Status = DfsGetRootReferralDataEx(pRootName,
&RemainingName,
&pReferralData,
&CacheHit);
if(Status == ERROR_SUCCESS)
{
pRefInfo = (PDFS_ROOTREF_INFORMATION) new BYTE[sizeof(DFS_ROOTREF_INFORMATION)];
if(pRefInfo == NULL)
{
pReferralData->ReleaseReference();
Status = ERROR_NOT_ENOUGH_MEMORY;
}
else
{
pRefInfo->pReferralData = pReferralData;
RtlCopyMemory(&pRefInfo->RootGuid, pNewGuid, sizeof(GUID));
*pRefInformation = pRefInfo;
}
}
return Status;
}
DFSSTATUS
DfsCheckIfRootExist(
PUNICODE_STRING pName,
GUID *pNewGuid)
{
DFSSTATUS Status = ERROR_SUCCESS;
UNICODE_STRING ServerName, ShareName, Rest;
//
// Break up the path into name components.
//
Status = DfsGetPathComponents( pName,
&ServerName,
&ShareName,
&Rest );
if(Status == ERROR_SUCCESS)
{
Status = DfsCheckRootADObjectExistence(NULL,
&ShareName,
pNewGuid);
}
return Status;
}
DFSSTATUS
DfsGetADRootReferralData(
PUNICODE_STRING pRootName,
DfsReferralData **ppReferralData )
{
BOOLEAN SubStringMatch = FALSE;
DFSSTATUS Status = ERROR_SUCCESS;
NTSTATUS NtStatus = STATUS_SUCCESS;
NTSTATUS NtTempStatus = STATUS_SUCCESS;
DfsFolderReferralData *pReferralData = NULL;
PDFS_ROOTREF_INFORMATION pRefInfo = NULL;
BOOLEAN CacheHit = TRUE;
BOOLEAN RootExists = FALSE;
GUID NewGuid;
UNICODE_STRING RemainingName;
*ppReferralData = NULL;
DFS_TRACE_LOW(REFERRAL_SERVER, "[%!FUNC!- Level %!LEVEL!]Getting AD Root referral for %wZ\n", pRootName);
NtStatus = DfsPrefixTableAcquireWriteLock( DfsServerGlobalData.pRootReferralTable );
if ( NtStatus == STATUS_SUCCESS )
{
NtStatus = DfsFindUnicodePrefixLocked( DfsServerGlobalData.pRootReferralTable,
pRootName,
&RemainingName,
(PVOID *)&pRefInfo,
&SubStringMatch );
if (NtStatus == STATUS_SUCCESS)
{
DFS_TRACE_LOW(REFERRAL_SERVER, "[%!FUNC!- Level %!LEVEL!]Found cached, for %wZ, %p\n", pRootName, pReferralData);
if (pRefInfo->pReferralData->TimeToRefresh() == TRUE)
{
//initialize the new guid
RtlZeroMemory(&NewGuid, sizeof(NewGuid));
//see if the root actually exists
Status = DfsCheckIfRootExist(pRootName,
&NewGuid);
if(Status == ERROR_SUCCESS)
{
RootExists = TRUE;
NtStatus = STATUS_UNSUCCESSFUL;
}
else
{
NtTempStatus = DfsCacheRemoveADRootReferral(pRootName, NULL);
}
}
else
{
pReferralData = pRefInfo->pReferralData;
pReferralData->AcquireReference();
*ppReferralData = pReferralData;
}
}
else
{
//No data in our table. see if the root actually exists.
//if it does not exist, then we bail out
Status = DfsCheckIfRootExist(pRootName,
&NewGuid);
if(Status == ERROR_SUCCESS)
{
RootExists = TRUE;
}
}
DfsPrefixTableReleaseLock( DfsServerGlobalData.pRootReferralTable );
}
if(RootExists && (NtStatus != STATUS_SUCCESS))
{
Status = DfsGetADRootReferralInformation(pRootName,
&pRefInfo,
&NewGuid);
if (Status == ERROR_SUCCESS)
{
*ppReferralData = pRefInfo->pReferralData;
NtTempStatus = DfsCacheRemoveADRootReferral(pRootName, NULL);
NtTempStatus = DfsCacheInsertADRootReferral(pRootName, pRefInfo);
if(NtTempStatus != STATUS_SUCCESS)
{
delete [] pRefInfo;
}
DFS_TRACE_ERROR_LOW( NtTempStatus, REFERRAL_SERVER, "[%!FUNC!- Level %!LEVEL!]AD Root Referral, insert status %x\n",
NtTempStatus );
}
DFS_TRACE_ERROR_LOW(Status, REFERRAL_SERVER, "[%!FUNC!- Level %!LEVEL!]Generate AD ROOT referral, got %p, status %x\n",
pReferralData, Status);
}
DFS_TRACE_ERROR_HIGH( Status, REFERRAL_SERVER, "[%!FUNC!- Level %!LEVEL!]AD Root Referral for %wZ is %p, status %x\n",
pRootName, pReferralData, Status);
return Status;
}
BOOLEAN
DfsIsMachineDomainController()
{
return DfsServerGlobalData.IsDc;
}
DWORD
DfsGetNumReflectionThreads(void)
{
return DfsServerGlobalData.NumWorkerThreads;
}
DFSSTATUS
DfsSetupPrivileges (void)
{
DFSSTATUS Status = ERROR_SUCCESS;
//
// Get the SE_SECURITY_PRIVILEGE to read/write SACLs.
//
Status = DfsAdjustPrivilege(SE_SECURITY_PRIVILEGE, TRUE);
if(Status != ERROR_SUCCESS)
{
return FALSE;
}
//
// Get backup/restore privilege to bypass ACL checks.
//
Status = DfsAdjustPrivilege(SE_BACKUP_PRIVILEGE, TRUE);
if(Status != ERROR_SUCCESS)
{
return FALSE;
}
Status = DfsAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE);
if(Status != ERROR_SUCCESS)
{
return FALSE;
}
//disable stuff we don't need
Status = DfsAdjustPrivilege(SE_CREATE_TOKEN_PRIVILEGE, FALSE);
Status = DfsAdjustPrivilege(SE_LOCK_MEMORY_PRIVILEGE, FALSE);
Status = DfsAdjustPrivilege(SE_SYSTEMTIME_PRIVILEGE, FALSE);
Status = DfsAdjustPrivilege(SE_CREATE_PERMANENT_PRIVILEGE, FALSE);
Status = DfsAdjustPrivilege(SE_CREATE_PAGEFILE_PRIVILEGE, FALSE);
Status = DfsAdjustPrivilege(SE_DEBUG_PRIVILEGE, FALSE);
Status = DfsAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE, FALSE);
Status = DfsAdjustPrivilege(SE_PROF_SINGLE_PROCESS_PRIVILEGE, FALSE);
//now, remove anything disabled
Status = DfsRemoveDisabledPrivileges();
return Status;
}
DFSSTATUS
DfsGetRootCount(
PULONG pRootCount )
{
DfsStore *pStore;
DFSSTATUS Status = ERROR_SUCCESS;
ULONG RootCount;
ULONG TotalCount = 0;
//
// For each store registered, get the number of roots.
//
for (pStore = DfsServerGlobalData.pRegisteredStores;
pStore != NULL;
pStore = pStore->pNextRegisteredStore) {
Status = pStore->GetRootCount(&RootCount);
if (Status == ERROR_SUCCESS)
{
TotalCount += RootCount;
}
else
{
break;
}
}
if (Status == ERROR_SUCCESS)
{
*pRootCount = TotalCount;
}
return Status;
}
DFSSTATUS
DfsCheckServerRootHandlingCapability()
{
DFSSTATUS Status = ERROR_SUCCESS;
if (DfsLimitRoots() == TRUE)
{
ULONG RootCount = 0;
Status = DfsGetRootCount(&RootCount);
if (Status == ERROR_SUCCESS)
{
if (RootCount >= 1)
{
Status = ERROR_NOT_SUPPORTED;
}
}
}
return Status;
}