| File: System\DirectoryServices\ActiveDirectory\Locator.cs | Web Access |
| Project: src\runtime\src\libraries\System.DirectoryServices\src\System.DirectoryServices.csproj (System.DirectoryServices) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections; using System.Globalization; using System.Runtime.InteropServices; namespace System.DirectoryServices.ActiveDirectory { internal sealed class Locator { // To disable public/protected constructors for this class private Locator() { } internal static DomainControllerInfo GetDomainControllerInfo(string? computerName, string? domainName, string? siteName, long flags) { int errorCode = 0; DomainControllerInfo domainControllerInfo; errorCode = DsGetDcNameWrapper(computerName, domainName, siteName, flags, out domainControllerInfo); if (errorCode != 0) { throw ExceptionHelper.GetExceptionFromErrorCode(errorCode, domainName); } return domainControllerInfo; } internal static int DsGetDcNameWrapper(string? computerName, string? domainName, string? siteName, long flags, out DomainControllerInfo domainControllerInfo) { IntPtr pDomainControllerInfo = IntPtr.Zero; int result = 0; // empty siteName/computerName should be treated as null if ((computerName != null) && (computerName.Length == 0)) { computerName = null; } if ((siteName != null) && (siteName.Length == 0)) { siteName = null; } result = Interop.Netapi32.DsGetDcName(computerName, domainName, IntPtr.Zero, siteName, (int)(flags | (long)PrivateLocatorFlags.ReturnDNSName), out pDomainControllerInfo); if (result == 0) { try { // success case domainControllerInfo = new DomainControllerInfo(); Marshal.PtrToStructure(pDomainControllerInfo, domainControllerInfo); } finally { // free the buffer // what to do with error code?? if (pDomainControllerInfo != IntPtr.Zero) { result = Interop.Netapi32.NetApiBufferFree(pDomainControllerInfo); } } } else { domainControllerInfo = new DomainControllerInfo(); } return result; } internal static ArrayList EnumerateDomainControllers(DirectoryContext context, string? domainName, string? siteName, long dcFlags) { Hashtable? allDCs = null; ArrayList dcs = new ArrayList(); // // this api obtains the list of DCs/GCs based on dns records. The DCs/GCs that have registered // non site specific records for the domain/forest are returned. Additionally DCs/GCs that have registered site specific records // (site is either specified or defaulted to the site of the local machine) are also returned in this list. // if (siteName == null) { // // if the site name is not specified then we get the site specific records for the local machine's site (in the context of the domain/forest/application partition that is specified) // (sitename could still be null if the machine is not in any site for the specified domain/forest, in that case we don't look for any site specific records) // DomainControllerInfo domainControllerInfo; int errorCode = DsGetDcNameWrapper(null, domainName, null, dcFlags & (long)(PrivateLocatorFlags.GCRequired | PrivateLocatorFlags.DSWriteableRequired | PrivateLocatorFlags.OnlyLDAPNeeded), out domainControllerInfo); if (errorCode == 0) { siteName = domainControllerInfo.ClientSiteName; } else if (errorCode == Interop.Errors.ERROR_NO_SUCH_DOMAIN) { // return an empty collection return dcs; } else { throw ExceptionHelper.GetExceptionFromErrorCode(errorCode); } } // this will get both the non site specific and the site specific records allDCs = DnsGetDcWrapper(domainName, siteName, dcFlags); foreach (string dcName in allDCs.Keys) { DirectoryContext dcContext = Utils.GetNewDirectoryContext(dcName, DirectoryContextType.DirectoryServer, context); if ((dcFlags & (long)PrivateLocatorFlags.GCRequired) != 0) { // add a GlobalCatalog object dcs.Add(new GlobalCatalog(dcContext, dcName)); } else { // add a domain controller object dcs.Add(new DomainController(dcContext, dcName)); } } return dcs; } private static Hashtable DnsGetDcWrapper(string? domainName, string? siteName, long dcFlags) { Hashtable domainControllers = new Hashtable(); int optionFlags = 0; IntPtr retGetDcContext = IntPtr.Zero; IntPtr sockAddressCountPtr = IntPtr.Zero; IntPtr sockAddressList = IntPtr.Zero; IntPtr dcDnsHostNamePtr = IntPtr.Zero; string? dcDnsHostName = null; int result = 0; result = Interop.Netapi32.DsGetDcOpen(domainName, (int)optionFlags, siteName, IntPtr.Zero, null, (int)dcFlags, out retGetDcContext); if (result == 0) { try { result = Interop.Netapi32.DsGetDcNext(retGetDcContext, out sockAddressCountPtr, out sockAddressList, out dcDnsHostNamePtr); if (result != 0 && result != Interop.Errors.ERROR_FILEMARK_DETECTED && result != Interop.Errors.DNS_ERROR_RCODE_NAME_ERROR && result != Interop.Errors.ERROR_NO_MORE_ITEMS) { throw ExceptionHelper.GetExceptionFromErrorCode(result); } while (result != Interop.Errors.ERROR_NO_MORE_ITEMS) { if (result != Interop.Errors.ERROR_FILEMARK_DETECTED && result != Interop.Errors.DNS_ERROR_RCODE_NAME_ERROR) { try { dcDnsHostName = Marshal.PtrToStringUni(dcDnsHostNamePtr)!; string key = dcDnsHostName.ToLowerInvariant(); if (!domainControllers.Contains(key)) { domainControllers.Add(key, null); } } finally { if (sockAddressList != IntPtr.Zero) { Marshal.FreeHGlobal(sockAddressList); } // what to do with the error? if (dcDnsHostNamePtr != IntPtr.Zero) { result = Interop.Netapi32.NetApiBufferFree(dcDnsHostNamePtr); } } } result = Interop.Netapi32.DsGetDcNext(retGetDcContext, out sockAddressCountPtr, out sockAddressList, out dcDnsHostNamePtr); if (result != 0 && result != Interop.Errors.ERROR_FILEMARK_DETECTED && result != Interop.Errors.DNS_ERROR_RCODE_NAME_ERROR && result != Interop.Errors.ERROR_NO_MORE_ITEMS) { throw ExceptionHelper.GetExceptionFromErrorCode(result); } } } finally { Interop.Netapi32.DsGetDcClose(retGetDcContext); } } else if (result != 0) { throw ExceptionHelper.GetExceptionFromErrorCode(result); } return domainControllers; } } }