1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System.Text;
6 using System.Collections;
7 using System.ComponentModel;
8 using System.Diagnostics;
9 using System.Runtime.InteropServices;
10 
11 namespace System.DirectoryServices.ActiveDirectory
12 {
13     public class ConfigurationSet
14     {
15         // Private Variables
16         private readonly DirectoryContext _context = null;
17         private readonly DirectoryEntryManager _directoryEntryMgr = null;
18         private bool _disposed = false;
19 
20         // variables corresponding to public properties
21         private readonly string _configSetName = null;
22         private ReadOnlySiteCollection _cachedSites = null;
23         private AdamInstanceCollection _cachedADAMInstances = null;
24         private ApplicationPartitionCollection _cachedApplicationPartitions = null;
25         private ActiveDirectorySchema _cachedSchema = null;
26         private AdamInstance _cachedSchemaRoleOwner = null;
27         private AdamInstance _cachedNamingRoleOwner = null;
28         private ReplicationSecurityLevel _cachedSecurityLevel = (ReplicationSecurityLevel)(-1);
29 
30         // 4 minutes timeout for locating an ADAM instance in the configset
31         private static TimeSpan s_locationTimeout = new TimeSpan(0, 4, 0);
32 
33         #region constructors
ConfigurationSet(DirectoryContext context, string configSetName, DirectoryEntryManager directoryEntryMgr)34         internal ConfigurationSet(DirectoryContext context, string configSetName, DirectoryEntryManager directoryEntryMgr)
35         {
36             _context = context;
37             _configSetName = configSetName;
38             _directoryEntryMgr = directoryEntryMgr;
39         }
40 
ConfigurationSet(DirectoryContext context, string configSetName)41         internal ConfigurationSet(DirectoryContext context, string configSetName)
42             : this(context, configSetName, new DirectoryEntryManager(context))
43         {
44         }
45         #endregion constructors
46 
47         #region IDisposable
48 
Dispose()49         public void Dispose() => Dispose(true);
50 
51         // private Dispose method
Dispose(bool disposing)52         protected virtual void Dispose(bool disposing)
53         {
54             if (!_disposed)
55             {
56                 // check if this is an explicit Dispose
57                 // only then clean up the directory entries
58                 if (disposing)
59                 {
60                     // dispose all directory entries
61                     foreach (DirectoryEntry entry in _directoryEntryMgr.GetCachedDirectoryEntries())
62                     {
63                         entry.Dispose();
64                     }
65                 }
66                 _disposed = true;
67             }
68         }
69         #endregion IDisposable
70 
71         #region public methods
72 
GetConfigurationSet(DirectoryContext context)73         public static ConfigurationSet GetConfigurationSet(DirectoryContext context)
74         {
75             // check that the argument is not null
76             if (context == null)
77                 throw new ArgumentNullException("context");
78 
79             // target should ConfigurationSet or DirectoryServer
80             if ((context.ContextType != DirectoryContextType.ConfigurationSet) &&
81                 (context.ContextType != DirectoryContextType.DirectoryServer))
82             {
83                 throw new ArgumentException(SR.TargetShouldBeServerORConfigSet, "context");
84             }
85 
86             // target should be an adam config set or server
87             if (((!context.isServer()) && (!context.isADAMConfigSet())))
88             {
89                 // the target should be a server or an ADAM Config Set
90                 if (context.ContextType == DirectoryContextType.ConfigurationSet)
91                 {
92                     throw new ActiveDirectoryObjectNotFoundException(SR.ConfigSetNotFound, typeof(ConfigurationSet), context.Name);
93                 }
94                 else
95                 {
96                     throw new ActiveDirectoryObjectNotFoundException(SR.Format(SR.AINotFound , context.Name), typeof(ConfigurationSet), null);
97                 }
98             }
99 
100             //  work with copy of the context
101             context = new DirectoryContext(context);
102 
103             //
104             // bind to rootdse of an adam instance (if target is already a server, verify that it is an adam instance)
105             //
106             DirectoryEntryManager directoryEntryMgr = new DirectoryEntryManager(context);
107             DirectoryEntry rootDSE = null;
108             string configSetName = null;
109 
110             try
111             {
112                 rootDSE = directoryEntryMgr.GetCachedDirectoryEntry(WellKnownDN.RootDSE);
113                 if ((context.isServer()) && (!Utils.CheckCapability(rootDSE, Capability.ActiveDirectoryApplicationMode)))
114                 {
115                     throw new ActiveDirectoryObjectNotFoundException(SR.Format(SR.AINotFound , context.Name), typeof(ConfigurationSet), null);
116                 }
117 
118                 configSetName = (string)PropertyManager.GetPropertyValue(context, rootDSE, PropertyManager.ConfigurationNamingContext);
119             }
120             catch (COMException e)
121             {
122                 int errorCode = e.ErrorCode;
123 
124                 if (errorCode == unchecked((int)0x8007203a))
125                 {
126                     if (context.ContextType == DirectoryContextType.ConfigurationSet)
127                     {
128                         throw new ActiveDirectoryObjectNotFoundException(SR.ConfigSetNotFound, typeof(ConfigurationSet), context.Name);
129                     }
130                     else
131                     {
132                         throw new ActiveDirectoryObjectNotFoundException(SR.Format(SR.AINotFound , context.Name), typeof(ConfigurationSet), null);
133                     }
134                 }
135                 else
136                 {
137                     throw ExceptionHelper.GetExceptionFromCOMException(context, e);
138                 }
139             }
140             catch (ActiveDirectoryObjectNotFoundException)
141             {
142                 if (context.ContextType == DirectoryContextType.ConfigurationSet)
143                 {
144                     // this is the case when we could not find an ADAM instance in that config set
145                     throw new ActiveDirectoryObjectNotFoundException(SR.ConfigSetNotFound, typeof(ConfigurationSet), context.Name);
146                 }
147                 else
148                     throw;
149             }
150 
151             // return config set object
152             return new ConfigurationSet(context, configSetName, directoryEntryMgr);
153         }
154 
FindAdamInstance()155         public AdamInstance FindAdamInstance()
156         {
157             CheckIfDisposed();
158             return FindOneAdamInstance(Name, _context, null, null);
159         }
160 
FindAdamInstance(string partitionName)161         public AdamInstance FindAdamInstance(string partitionName)
162         {
163             CheckIfDisposed();
164 
165             if (partitionName == null)
166             {
167                 throw new ArgumentNullException("partitionName");
168             }
169 
170             return FindOneAdamInstance(Name, _context, partitionName, null);
171         }
172 
FindAdamInstance(string partitionName, string siteName)173         public AdamInstance FindAdamInstance(string partitionName, string siteName)
174         {
175             CheckIfDisposed();
176 
177             //
178             // null partitionName would signify that we don't care about the partition
179             //
180 
181             if (siteName == null)
182             {
183                 throw new ArgumentNullException("siteName");
184             }
185 
186             return FindOneAdamInstance(Name, _context, partitionName, siteName);
187         }
188 
FindAllAdamInstances()189         public AdamInstanceCollection FindAllAdamInstances()
190         {
191             CheckIfDisposed();
192 
193             return FindAdamInstances(_context, null, null);
194         }
195 
FindAllAdamInstances(string partitionName)196         public AdamInstanceCollection FindAllAdamInstances(string partitionName)
197         {
198             CheckIfDisposed();
199 
200             if (partitionName == null)
201             {
202                 throw new ArgumentNullException("partitionName");
203             }
204 
205             return FindAdamInstances(_context, partitionName, null);
206         }
207 
FindAllAdamInstances(string partitionName, string siteName)208         public AdamInstanceCollection FindAllAdamInstances(string partitionName, string siteName)
209         {
210             CheckIfDisposed();
211 
212             //
213             // null partitionName would signify that we don't care about the partition
214             //
215 
216             if (siteName == null)
217             {
218                 throw new ArgumentNullException("siteName");
219             }
220 
221             return FindAdamInstances(_context, partitionName, siteName);
222         }
223 
GetDirectoryEntry()224         public DirectoryEntry GetDirectoryEntry()
225         {
226             CheckIfDisposed();
227             return DirectoryEntryManager.GetDirectoryEntry(_context, WellKnownDN.ConfigurationNamingContext);
228         }
229 
GetSecurityLevel()230         public ReplicationSecurityLevel GetSecurityLevel()
231         {
232             CheckIfDisposed();
233             if (_cachedSecurityLevel == (ReplicationSecurityLevel)(-1))
234             {
235                 DirectoryEntry configEntry = _directoryEntryMgr.GetCachedDirectoryEntry(WellKnownDN.ConfigurationNamingContext);
236                 _cachedSecurityLevel = (ReplicationSecurityLevel)((int)PropertyManager.GetPropertyValue(_context, configEntry, PropertyManager.MsDSReplAuthenticationMode));
237             }
238             return _cachedSecurityLevel;
239         }
240 
SetSecurityLevel(ReplicationSecurityLevel securityLevel)241         public void SetSecurityLevel(ReplicationSecurityLevel securityLevel)
242         {
243             CheckIfDisposed();
244             if (securityLevel < ReplicationSecurityLevel.NegotiatePassThrough || securityLevel > ReplicationSecurityLevel.MutualAuthentication)
245             {
246                 throw new InvalidEnumArgumentException("securityLevel", (int)securityLevel, typeof(ReplicationSecurityLevel));
247             }
248 
249             try
250             {
251                 DirectoryEntry configEntry = _directoryEntryMgr.GetCachedDirectoryEntry(WellKnownDN.ConfigurationNamingContext);
252                 configEntry.Properties[PropertyManager.MsDSReplAuthenticationMode].Value = (int)securityLevel;
253                 configEntry.CommitChanges();
254             }
255             catch (COMException e)
256             {
257                 throw ExceptionHelper.GetExceptionFromCOMException(_context, e);
258             }
259 
260             // invalidate the cached entry
261             _cachedSecurityLevel = (ReplicationSecurityLevel)(-1);
262         }
263 
ToString()264         public override string ToString() => Name;
265 
266         #endregion public methods
267 
268         #region public properties
269 
270         public string Name
271         {
272             get
273             {
274                 CheckIfDisposed();
275                 return _configSetName;
276             }
277         }
278 
279         public ReadOnlySiteCollection Sites
280         {
281             get
282             {
283                 CheckIfDisposed();
284                 if (_cachedSites == null)
285                 {
286                     _cachedSites = new ReadOnlySiteCollection(GetSites());
287                 }
288                 return _cachedSites;
289             }
290         }
291 
292         public AdamInstanceCollection AdamInstances
293         {
294             get
295             {
296                 CheckIfDisposed();
297                 if (_cachedADAMInstances == null)
298                 {
299                     _cachedADAMInstances = FindAllAdamInstances();
300                 }
301                 return _cachedADAMInstances;
302             }
303         }
304 
305         public ApplicationPartitionCollection ApplicationPartitions
306         {
307             get
308             {
309                 CheckIfDisposed();
310                 if (_cachedApplicationPartitions == null)
311                 {
312                     _cachedApplicationPartitions = new ApplicationPartitionCollection(GetApplicationPartitions());
313                 }
314                 return _cachedApplicationPartitions;
315             }
316         }
317 
318         public ActiveDirectorySchema Schema
319         {
320             get
321             {
322                 CheckIfDisposed();
323                 if (_cachedSchema == null)
324                 {
325                     try
326                     {
327                         _cachedSchema = new ActiveDirectorySchema(_context, _directoryEntryMgr.ExpandWellKnownDN(WellKnownDN.SchemaNamingContext));
328                     }
329                     catch (COMException e)
330                     {
331                         throw ExceptionHelper.GetExceptionFromCOMException(_context, e);
332                     }
333                 }
334                 return _cachedSchema;
335             }
336         }
337 
338         public AdamInstance SchemaRoleOwner
339         {
340             get
341             {
342                 CheckIfDisposed();
343                 if (_cachedSchemaRoleOwner == null)
344                 {
345                     _cachedSchemaRoleOwner = GetRoleOwner(AdamRole.SchemaRole);
346                 }
347                 return _cachedSchemaRoleOwner;
348             }
349         }
350 
351         public AdamInstance NamingRoleOwner
352         {
353             get
354             {
355                 CheckIfDisposed();
356                 if (_cachedNamingRoleOwner == null)
357                 {
358                     _cachedNamingRoleOwner = GetRoleOwner(AdamRole.NamingRole);
359                 }
360                 return _cachedNamingRoleOwner;
361             }
362         }
363 
364         #endregion public properties
365 
366         #region private methods
367 
GetSearchRootEntry(Forest forest)368         private static DirectoryEntry GetSearchRootEntry(Forest forest)
369         {
370             DirectoryEntry rootEntry;
371             DirectoryContext forestContext = forest.GetDirectoryContext();
372             bool isServer = false;
373             bool isGC = false;
374             AuthenticationTypes authType = Utils.DefaultAuthType;
375 
376             if (forestContext.ContextType == DirectoryContextType.DirectoryServer)
377             {
378                 //
379                 // the forest object was created by specifying a server name
380                 // so we will stick to that server for the search. We need to determine
381                 // whether or not the server is a DC or GC
382                 //
383                 isServer = true;
384                 DirectoryEntry rootDSE = DirectoryEntryManager.GetDirectoryEntry(forestContext, WellKnownDN.RootDSE);
385                 string isGCReady = (string)PropertyManager.GetPropertyValue(forestContext, rootDSE, PropertyManager.IsGlobalCatalogReady);
386                 isGC = (Utils.Compare(isGCReady, "TRUE") == 0);
387             }
388 
389             if (isServer)
390             {
391                 authType |= AuthenticationTypes.ServerBind;
392 
393                 if (isGC)
394                 {
395                     rootEntry = new DirectoryEntry("GC://" + forestContext.GetServerName(), forestContext.UserName, forestContext.Password, authType);
396                 }
397                 else
398                 {
399                     rootEntry = new DirectoryEntry("LDAP://" + forestContext.GetServerName(), forestContext.UserName, forestContext.Password, authType);
400                 }
401             }
402             else
403             {
404                 // need to find any GC in the forest
405                 rootEntry = new DirectoryEntry("GC://" + forest.Name, forestContext.UserName, forestContext.Password, authType);
406             }
407 
408             return rootEntry;
409         }
410 
FindAnyAdamInstance(DirectoryContext context)411         internal static AdamInstance FindAnyAdamInstance(DirectoryContext context)
412         {
413             if (context.ContextType != DirectoryContextType.ConfigurationSet)
414             {
415                 // assuming it's an ADAM Instance
416                 // check that it is an ADAM server only (not AD)
417                 DirectoryEntryManager directoryEntryMgr = new DirectoryEntryManager(context);
418                 DirectoryEntry rootDSE = directoryEntryMgr.GetCachedDirectoryEntry(WellKnownDN.RootDSE);
419 
420                 if (!Utils.CheckCapability(rootDSE, Capability.ActiveDirectoryApplicationMode))
421                 {
422                     directoryEntryMgr.RemoveIfExists(directoryEntryMgr.ExpandWellKnownDN(WellKnownDN.RootDSE));
423                     throw new ArgumentException(SR.TargetShouldBeServerORConfigSet, "context");
424                 }
425 
426                 string dnsHostName = (string)PropertyManager.GetPropertyValue(context, rootDSE, PropertyManager.DnsHostName);
427 
428                 return new AdamInstance(context, dnsHostName, directoryEntryMgr);
429             }
430 
431             // Now this is the case where context is a Config Set
432             // Here we need to search for the service connection points in the forest
433             // (if the forest object was created by specifying the server, we stick to that, else search in a GC)
434             DirectoryEntry rootEntry = GetSearchRootEntry(Forest.GetCurrentForest());
435             ArrayList adamInstanceNames = new ArrayList();
436 
437             try
438             {
439                 string entryName = (string)rootEntry.Properties["distinguishedName"].Value;
440 
441                 // Search for computer "serviceConnectionObjects" where the keywords attribute
442                 // contains the specified keyword
443                 // set up the searcher object
444 
445                 // build the filter
446                 StringBuilder str = new StringBuilder(15);
447                 str.Append("(&(");
448                 str.Append(PropertyManager.ObjectCategory);
449                 str.Append("=serviceConnectionPoint)");
450                 str.Append("(");
451                 str.Append(PropertyManager.Keywords);
452                 str.Append("=1.2.840.113556.1.4.1851)(");
453                 str.Append(PropertyManager.Keywords);
454                 str.Append("=");
455                 str.Append(Utils.GetEscapedFilterValue(context.Name)); // target = config set name
456                 str.Append("))");
457 
458                 string filter = str.ToString();
459                 string[] propertiesToLoad = new string[1];
460 
461                 propertiesToLoad[0] = PropertyManager.ServiceBindingInformation;
462 
463                 ADSearcher searcher = new ADSearcher(rootEntry, filter, propertiesToLoad, SearchScope.Subtree, false /*not paged search*/, false /*no cached results*/);
464                 SearchResultCollection resCol = searcher.FindAll();
465 
466                 try
467                 {
468                     foreach (SearchResult res in resCol)
469                     {
470                         // the binding info contains two values
471                         // "ldap://hostname:ldapport"
472                         // and "ldaps://hostname:sslport"
473                         // we need the "hostname:ldapport" value
474                         string prefix = "ldap://";
475 
476                         foreach (string bindingInfo in res.Properties[PropertyManager.ServiceBindingInformation])
477                         {
478                             if ((bindingInfo.Length > prefix.Length) && (String.Compare(bindingInfo.Substring(0, prefix.Length), prefix, StringComparison.OrdinalIgnoreCase) == 0))
479                             {
480                                 adamInstanceNames.Add(bindingInfo.Substring(prefix.Length));
481                             }
482                         }
483                     }
484                 }
485                 finally
486                 {
487                     resCol.Dispose();
488                 }
489             }
490             catch (COMException e)
491             {
492                 throw ExceptionHelper.GetExceptionFromCOMException(context, e);
493             }
494             finally
495             {
496                 rootEntry.Dispose();
497             }
498 
499             //
500             // we have all the adam instance names in teh form of server:port from the scp
501             // now we need to find one that is alive
502             //
503             return FindAliveAdamInstance(null, context, adamInstanceNames);
504         }
505 
FindOneAdamInstance(DirectoryContext context, string partitionName, string siteName)506         internal static AdamInstance FindOneAdamInstance(DirectoryContext context, string partitionName, string siteName)
507         {
508             return FindOneAdamInstance(null, context, partitionName, siteName);
509         }
510 
FindOneAdamInstance(string configSetName, DirectoryContext context, string partitionName, string siteName)511         internal static AdamInstance FindOneAdamInstance(string configSetName, DirectoryContext context, string partitionName, string siteName)
512         {
513             // can expect valid context (non-null)
514             if (partitionName != null && partitionName.Length == 0)
515             {
516                 throw new ArgumentException(SR.EmptyStringParameter, "partitionName");
517             }
518 
519             if (siteName != null && siteName.Length == 0)
520             {
521                 throw new ArgumentException(SR.EmptyStringParameter, "siteName");
522             }
523 
524             ArrayList ntdsaNames = Utils.GetReplicaList(context, partitionName, siteName, false /* isDefaultNC */, true /* isADAM */, false /* mustBeGC */);
525 
526             if (ntdsaNames.Count < 1)
527             {
528                 throw new ActiveDirectoryObjectNotFoundException(SR.ADAMInstanceNotFound, typeof(AdamInstance), null);
529             }
530 
531             return FindAliveAdamInstance(configSetName, context, ntdsaNames);
532         }
533 
FindAdamInstances(DirectoryContext context, string partitionName, string siteName)534         internal static AdamInstanceCollection FindAdamInstances(DirectoryContext context, string partitionName, string siteName)
535         {
536             // can expect valid context (non-null)
537             if (partitionName != null && partitionName.Length == 0)
538             {
539                 throw new ArgumentException(SR.EmptyStringParameter, "partitionName");
540             }
541 
542             if (siteName != null && siteName.Length == 0)
543             {
544                 throw new ArgumentException(SR.EmptyStringParameter, "siteName");
545             }
546 
547             ArrayList adamInstanceList = new ArrayList();
548 
549             foreach (string adamInstanceName in Utils.GetReplicaList(context, partitionName, siteName, false /* isDefaultNC */, true /* isADAM */, false /* mustBeGC */))
550             {
551                 DirectoryContext adamInstContext = Utils.GetNewDirectoryContext(adamInstanceName, DirectoryContextType.DirectoryServer, context);
552                 adamInstanceList.Add(new AdamInstance(adamInstContext, adamInstanceName));
553             }
554 
555             return new AdamInstanceCollection(adamInstanceList);
556         }
557 
558         //
559         // The input to this function is a list of adam instance names in the form server:port
560         // This function tries to bind to each of the instances in this list sequentially until one of the following occurs:
561         // 1.  An ADAM instance responds to an ldap_bind - we return an ADAMInstance object for that adam instance
562         // 2.  We exceed the timeout duration - we return an ActiveDirectoryObjectNotFoundException
563         //
FindAliveAdamInstance(string configSetName, DirectoryContext context, ArrayList adamInstanceNames)564         internal static AdamInstance FindAliveAdamInstance(string configSetName, DirectoryContext context, ArrayList adamInstanceNames)
565         {
566             bool foundAliveADAMInstance = false;
567             AdamInstance adamInstance = null;
568 
569             // record the start time so that we can determine if the timeout duration has been exceeded or not
570             DateTime startTime = DateTime.UtcNow;
571 
572             // loop through each adam instance and try to bind to the rootdse
573             foreach (string adamInstanceName in adamInstanceNames)
574             {
575                 DirectoryContext adamInstContext = Utils.GetNewDirectoryContext(adamInstanceName, DirectoryContextType.DirectoryServer, context);
576                 DirectoryEntryManager directoryEntryMgr = new DirectoryEntryManager(adamInstContext);
577                 DirectoryEntry tempRootEntry = directoryEntryMgr.GetCachedDirectoryEntry(WellKnownDN.RootDSE);
578 
579                 try
580                 {
581                     tempRootEntry.Bind(true);
582                     adamInstance = new AdamInstance(adamInstContext, adamInstanceName, directoryEntryMgr, true /* nameIncludesPort */);
583                     foundAliveADAMInstance = true;
584                 }
585                 catch (COMException e)
586                 {
587                     // if this is server down /server busy / server unavailable / timeout  exception we should just eat this up and try the next one
588                     if ((e.ErrorCode == unchecked((int)0x8007203a)) ||
589                         (e.ErrorCode == unchecked((int)0x8007200e)) ||
590                         (e.ErrorCode == unchecked((int)0x8007200f)) ||
591                         (e.ErrorCode == unchecked((int)0x800705b4)))
592                     {
593                         // if we are passed the timeout period, we should throw, else do nothing
594                         if (DateTime.UtcNow.Subtract(startTime) > s_locationTimeout)
595                             throw new ActiveDirectoryObjectNotFoundException(SR.Format(SR.ADAMInstanceNotFoundInConfigSet , (configSetName != null) ? configSetName : context.Name), typeof(AdamInstance), null);
596                     }
597                     else
598                         throw ExceptionHelper.GetExceptionFromCOMException(context, e);
599                 }
600 
601                 if (foundAliveADAMInstance)
602                 {
603                     return adamInstance;
604                 }
605             }
606 
607             // if we reach here, we haven't found an adam instance
608             throw new ActiveDirectoryObjectNotFoundException(SR.Format(SR.ADAMInstanceNotFoundInConfigSet , (configSetName != null) ? configSetName : context.Name), typeof(AdamInstance), null);
609         }
610 
611         /// <returns>Returns a DomainController object for the DC that holds the specified FSMO role</returns>
GetRoleOwner(AdamRole role)612         private AdamInstance GetRoleOwner(AdamRole role)
613         {
614             DirectoryEntry entry = null;
615 
616             string adamInstName = null;
617             try
618             {
619                 switch (role)
620                 {
621                     case AdamRole.SchemaRole:
622                         {
623                             entry = _directoryEntryMgr.GetCachedDirectoryEntry(WellKnownDN.SchemaNamingContext);
624                             break;
625                         }
626 
627                     case AdamRole.NamingRole:
628                         {
629                             entry = _directoryEntryMgr.GetCachedDirectoryEntry(WellKnownDN.PartitionsContainer);
630                             break;
631                         }
632 
633                     default:
634                         // should not happen since we are calling this only internally
635                         Debug.Assert(false, "ConfigurationSet.GetRoleOwner: Invalid role type.");
636                         break;
637                 }
638                 entry.RefreshCache();
639                 adamInstName = Utils.GetAdamDnsHostNameFromNTDSA(_context, (string)PropertyManager.GetPropertyValue(_context, entry, PropertyManager.FsmoRoleOwner));
640             }
641             catch (COMException e)
642             {
643                 throw ExceptionHelper.GetExceptionFromCOMException(_context, e);
644             }
645             finally
646             {
647                 if (entry != null)
648                 {
649                     entry.Dispose();
650                 }
651             }
652 
653             // create a new context object for the adam instance passing on  the
654             // credentials from the context
655             DirectoryContext adamInstContext = Utils.GetNewDirectoryContext(adamInstName, DirectoryContextType.DirectoryServer, _context);
656 
657             return new AdamInstance(adamInstContext, adamInstName);
658         }
659 
GetSites()660         private ArrayList GetSites()
661         {
662             ArrayList sites = new ArrayList();
663             DirectoryEntry sitesEntry = _directoryEntryMgr.GetCachedDirectoryEntry(WellKnownDN.SitesContainer);
664 
665             // search for all the "site" objects
666             // (one-level search is good enough)
667             // setup the directory searcher object
668             string filter = "(" + PropertyManager.ObjectCategory + "=site)";
669             string[] propertiesToLoad = new string[1];
670 
671             propertiesToLoad[0] = PropertyManager.Cn;
672 
673             ADSearcher searcher = new ADSearcher(sitesEntry, filter, propertiesToLoad, SearchScope.OneLevel);
674             SearchResultCollection resCol = null;
675 
676             try
677             {
678                 resCol = searcher.FindAll();
679 
680                 foreach (SearchResult res in resCol)
681                 {
682                     // an existing site
683                     sites.Add(new ActiveDirectorySite(_context, (string)PropertyManager.GetSearchResultPropertyValue(res, PropertyManager.Cn), true));
684                 }
685             }
686             catch (COMException e)
687             {
688                 throw ExceptionHelper.GetExceptionFromCOMException(_context, e);
689             }
690             finally
691             {
692                 if (resCol != null)
693                 {
694                     // call dispose on search result collection
695                     resCol.Dispose();
696                 }
697             }
698             return sites;
699         }
700 
GetApplicationPartitions()701         private ArrayList GetApplicationPartitions()
702         {
703             ArrayList appNCs = new ArrayList();
704             DirectoryEntry rootDSE = _directoryEntryMgr.GetCachedDirectoryEntry(WellKnownDN.RootDSE);
705             DirectoryEntry partitionsEntry = _directoryEntryMgr.GetCachedDirectoryEntry(WellKnownDN.PartitionsContainer);
706 
707             // search for all the "crossRef" objects that have the
708             // ADS_SYSTEMFLAG_CR_NTDS_NC set and the SYSTEMFLAG_CR_NTDS_DOMAIN flag not set
709             // (one-level search is good enough)
710             // setup the directory searcher object
711 
712             // build the filter
713             StringBuilder str = new StringBuilder(100);
714             str.Append("(&(");
715             str.Append(PropertyManager.ObjectCategory);
716             str.Append("=crossRef)(");
717             str.Append(PropertyManager.SystemFlags);
718             str.Append(":1.2.840.113556.1.4.804:=");
719             str.Append((int)SystemFlag.SystemFlagNtdsNC);
720             str.Append(")(!(");
721             str.Append(PropertyManager.SystemFlags);
722             str.Append(":1.2.840.113556.1.4.803:=");
723             str.Append((int)SystemFlag.SystemFlagNtdsDomain);
724             str.Append(")))");
725 
726             string filter = str.ToString();
727             string[] propertiesToLoad = new string[2];
728             propertiesToLoad[0] = PropertyManager.NCName;
729             propertiesToLoad[1] = PropertyManager.MsDSNCReplicaLocations;
730 
731             ADSearcher searcher = new ADSearcher(partitionsEntry, filter, propertiesToLoad, SearchScope.OneLevel);
732             SearchResultCollection resCol = null;
733 
734             try
735             {
736                 resCol = searcher.FindAll();
737 
738                 string schemaNamingContext = (string)PropertyManager.GetPropertyValue(_context, rootDSE, PropertyManager.SchemaNamingContext);
739                 string configurationNamingContext = (string)PropertyManager.GetPropertyValue(_context, rootDSE, PropertyManager.ConfigurationNamingContext);
740 
741                 foreach (SearchResult res in resCol)
742                 {
743                     // add the name of the appNC only if it is not
744                     // the Schema or Configuration partition
745                     string nCName = (string)PropertyManager.GetSearchResultPropertyValue(res, PropertyManager.NCName);
746 
747                     if ((!(nCName.Equals(schemaNamingContext))) && (!(nCName.Equals(configurationNamingContext))))
748                     {
749                         ResultPropertyValueCollection replicaLocations = res.Properties[PropertyManager.MsDSNCReplicaLocations];
750                         if (replicaLocations.Count > 0)
751                         {
752                             string replicaName = Utils.GetAdamDnsHostNameFromNTDSA(_context, (string)replicaLocations[Utils.GetRandomIndex(replicaLocations.Count)]);
753                             DirectoryContext appNCContext = Utils.GetNewDirectoryContext(replicaName, DirectoryContextType.DirectoryServer, _context);
754                             appNCs.Add(new ApplicationPartition(appNCContext, nCName, null, ApplicationPartitionType.ADAMApplicationPartition, new DirectoryEntryManager(appNCContext)));
755                         }
756                     }
757                 }
758             }
759             catch (COMException e)
760             {
761                 throw ExceptionHelper.GetExceptionFromCOMException(_context, e);
762             }
763             finally
764             {
765                 if (resCol != null)
766                 {
767                     // call dispose on search result collection
768                     resCol.Dispose();
769                 }
770             }
771             return appNCs;
772         }
773 
CheckIfDisposed()774         private void CheckIfDisposed()
775         {
776             if (_disposed)
777             {
778                 throw new ObjectDisposedException(GetType().Name);
779             }
780         }
781         #endregion private methods
782     }
783 }
784