//+---------------------------------------------------------------------------- // // 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 #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 . // 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; }