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.Net;
6 using System.ComponentModel;
7 using System.Collections;
8 using System.Globalization;
9 using System.Runtime.InteropServices;
10 using System.Diagnostics;
11 
12 namespace System.DirectoryServices.ActiveDirectory
13 {
14     [Flags]
15     public enum SyncFromAllServersOptions
16     {
17         None = 0,
18         AbortIfServerUnavailable = 1,
19         SyncAdjacentServerOnly = 2,
20         CheckServerAlivenessOnly = 0x8,
21         SkipInitialCheck = 0x10,
22         PushChangeOutward = 0x20,
23         CrossSite = 0x40
24     }
25     public enum SyncFromAllServersEvent
26     {
27         Error = 0,
28         SyncStarted = 1,
29         SyncCompleted = 2,
30         Finished = 3
31     }
32     public enum SyncFromAllServersErrorCategory
33     {
34         ErrorContactingServer = 0,
35         ErrorReplicating = 1,
36         ServerUnreachable = 2
37     }
SyncUpdateCallback(SyncFromAllServersEvent eventType, string targetServer, string sourceServer, SyncFromAllServersOperationException exception)38     public delegate bool SyncUpdateCallback(SyncFromAllServersEvent eventType, string targetServer, string sourceServer, SyncFromAllServersOperationException exception);
SyncReplicaFromAllServersCallback(IntPtr data, IntPtr update)39     internal delegate bool SyncReplicaFromAllServersCallback(IntPtr data, IntPtr update);
40 
41     public class DomainController : DirectoryServer
42     {
43         private IntPtr _dsHandle = IntPtr.Zero;
44         private IntPtr _authIdentity = IntPtr.Zero;
45         private readonly string[] _becomeRoleOwnerAttrs = null;
46         private bool _disposed = false;
47 
48         // internal variables for the public properties
49         private string _cachedComputerObjectName = null;
50         private string _cachedOSVersion = null;
51         private double _cachedNumericOSVersion = 0;
52         private Forest _currentForest = null;
53         private Domain _cachedDomain = null;
54         private ActiveDirectoryRoleCollection _cachedRoles = null;
55         private bool _dcInfoInitialized = false;
56 
57         internal SyncUpdateCallback userDelegate = null;
58         internal readonly SyncReplicaFromAllServersCallback syncAllFunctionPointer = null;
59 
60         // this is twice the maximum allowed RIDPool size which is 15k
61         internal const int UpdateRidPoolSeizureValue = 30000;
62 
63         #region constructors
64 
65         // Internal constructors
DomainController()66         protected DomainController()
67         {
68         }
69 
DomainController(DirectoryContext context, string domainControllerName)70         internal DomainController(DirectoryContext context, string domainControllerName)
71             : this(context, domainControllerName, new DirectoryEntryManager(context))
72         {
73         }
74 
DomainController(DirectoryContext context, string domainControllerName, DirectoryEntryManager directoryEntryMgr)75         internal DomainController(DirectoryContext context, string domainControllerName, DirectoryEntryManager directoryEntryMgr)
76         {
77             this.context = context;
78             this.replicaName = domainControllerName;
79             this.directoryEntryMgr = directoryEntryMgr;
80 
81             // initialize the transfer role owner attributes
82             _becomeRoleOwnerAttrs = new String[5];
83             _becomeRoleOwnerAttrs[0] = PropertyManager.BecomeSchemaMaster;
84             _becomeRoleOwnerAttrs[1] = PropertyManager.BecomeDomainMaster;
85             _becomeRoleOwnerAttrs[2] = PropertyManager.BecomePdc;
86             _becomeRoleOwnerAttrs[3] = PropertyManager.BecomeRidMaster;
87             _becomeRoleOwnerAttrs[4] = PropertyManager.BecomeInfrastructureMaster;
88 
89             // initialize the callback function
90             syncAllFunctionPointer = new SyncReplicaFromAllServersCallback(SyncAllCallbackRoutine);
91         }
92         #endregion constructors
93 
94         #region IDisposable
95 
~DomainController()96         ~DomainController() => Dispose(false);
97 
98         // private Dispose method
Dispose(bool disposing)99         protected override void Dispose(bool disposing)
100         {
101             if (!_disposed)
102             {
103                 try
104                 {
105                     // if there are any managed or unmanaged
106                     // resources to be freed, those should be done here
107                     // if disposing = true, only unmanaged resources should
108                     // be freed, else both managed and unmanaged.
109                     FreeDSHandle();
110                     _disposed = true;
111                 }
112                 finally
113                 {
114                     base.Dispose();
115                 }
116             }
117         }
118         #endregion IDisposable
119 
120         #region public methods
121 
GetDomainController(DirectoryContext context)122         public static DomainController GetDomainController(DirectoryContext context)
123         {
124             string dcDnsName = null;
125             DirectoryEntryManager directoryEntryMgr = null;
126 
127             // check that the context argument is not null
128             if (context == null)
129                 throw new ArgumentNullException("context");
130 
131             // target should be DC
132             if (context.ContextType != DirectoryContextType.DirectoryServer)
133             {
134                 throw new ArgumentException(SR.TargetShouldBeDC, "context");
135             }
136 
137             // target should be a server
138             if (!(context.isServer()))
139             {
140                 throw new ActiveDirectoryObjectNotFoundException(SR.Format(SR.DCNotFound , context.Name), typeof(DomainController), context.Name);
141             }
142 
143             //  work with copy of the context
144             context = new DirectoryContext(context);
145 
146             try
147             {
148                 // Get dns name of the dc
149                 // by binding to root dse and getting the "dnsHostName" attribute
150                 directoryEntryMgr = new DirectoryEntryManager(context);
151                 DirectoryEntry rootDSE = directoryEntryMgr.GetCachedDirectoryEntry(WellKnownDN.RootDSE);
152                 if (!Utils.CheckCapability(rootDSE, Capability.ActiveDirectory))
153                 {
154                     throw new ActiveDirectoryObjectNotFoundException(SR.Format(SR.DCNotFound , context.Name), typeof(DomainController), context.Name);
155                 }
156                 dcDnsName = (string)PropertyManager.GetPropertyValue(context, rootDSE, PropertyManager.DnsHostName);
157             }
158             catch (COMException e)
159             {
160                 int errorCode = e.ErrorCode;
161 
162                 if (errorCode == unchecked((int)0x8007203a))
163                 {
164                     throw new ActiveDirectoryObjectNotFoundException(SR.Format(SR.DCNotFound , context.Name), typeof(DomainController), context.Name);
165                 }
166                 else
167                 {
168                     throw ExceptionHelper.GetExceptionFromCOMException(context, e);
169                 }
170             }
171 
172             return new DomainController(context, dcDnsName, directoryEntryMgr);
173         }
174 
FindOne(DirectoryContext context)175         public static DomainController FindOne(DirectoryContext context)
176         {
177             if (context == null)
178             {
179                 throw new ArgumentNullException("context");
180             }
181 
182             if (context.ContextType != DirectoryContextType.Domain)
183             {
184                 throw new ArgumentException(SR.TargetShouldBeDomain, "context");
185             }
186 
187             return FindOneWithCredentialValidation(context, null, 0);
188         }
189 
FindOne(DirectoryContext context, string siteName)190         public static DomainController FindOne(DirectoryContext context, string siteName)
191         {
192             if (context == null)
193             {
194                 throw new ArgumentNullException("context");
195             }
196 
197             if (context.ContextType != DirectoryContextType.Domain)
198             {
199                 throw new ArgumentException(SR.TargetShouldBeDomain, "context");
200             }
201 
202             if (siteName == null)
203             {
204                 throw new ArgumentNullException("siteName");
205             }
206 
207             return FindOneWithCredentialValidation(context, siteName, 0);
208         }
209 
FindOne(DirectoryContext context, LocatorOptions flag)210         public static DomainController FindOne(DirectoryContext context, LocatorOptions flag)
211         {
212             if (context == null)
213             {
214                 throw new ArgumentNullException("context");
215             }
216 
217             if (context.ContextType != DirectoryContextType.Domain)
218             {
219                 throw new ArgumentException(SR.TargetShouldBeDomain, "context");
220             }
221 
222             return FindOneWithCredentialValidation(context, null, flag);
223         }
224 
FindOne(DirectoryContext context, string siteName, LocatorOptions flag)225         public static DomainController FindOne(DirectoryContext context, string siteName, LocatorOptions flag)
226         {
227             if (context == null)
228             {
229                 throw new ArgumentNullException("context");
230             }
231 
232             if (context.ContextType != DirectoryContextType.Domain)
233             {
234                 throw new ArgumentException(SR.TargetShouldBeDomain, "context");
235             }
236 
237             if (siteName == null)
238             {
239                 throw new ArgumentNullException("siteName");
240             }
241 
242             return FindOneWithCredentialValidation(context, siteName, flag);
243         }
244 
FindAll(DirectoryContext context)245         public static DomainControllerCollection FindAll(DirectoryContext context)
246         {
247             if (context == null)
248             {
249                 throw new ArgumentNullException("context");
250             }
251 
252             if (context.ContextType != DirectoryContextType.Domain)
253             {
254                 throw new ArgumentException(SR.TargetShouldBeDomain, "context");
255             }
256 
257             //  work with copy of the context
258             context = new DirectoryContext(context);
259 
260             return FindAllInternal(context, context.Name, false /* isDnsDomainName */, null);
261         }
262 
FindAll(DirectoryContext context, string siteName)263         public static DomainControllerCollection FindAll(DirectoryContext context, string siteName)
264         {
265             if (context == null)
266             {
267                 throw new ArgumentNullException("context");
268             }
269 
270             if (context.ContextType != DirectoryContextType.Domain)
271             {
272                 throw new ArgumentException(SR.TargetShouldBeDomain, "context");
273             }
274 
275             if (siteName == null)
276             {
277                 throw new ArgumentNullException("siteName");
278             }
279 
280             //  work with copy of the context
281             context = new DirectoryContext(context);
282 
283             return FindAllInternal(context, context.Name, false /* isDnsDomainName */, siteName);
284         }
285 
EnableGlobalCatalog()286         public virtual GlobalCatalog EnableGlobalCatalog()
287         {
288             CheckIfDisposed();
289 
290             try
291             {
292                 // bind to the server object
293                 DirectoryEntry serverNtdsaEntry = directoryEntryMgr.GetCachedDirectoryEntry(NtdsaObjectName);
294                 // set the NTDSDSA_OPT_IS_GC flag on the "options" property
295                 int options = 0;
296                 if (serverNtdsaEntry.Properties[PropertyManager.Options].Value != null)
297                 {
298                     options = (int)serverNtdsaEntry.Properties[PropertyManager.Options].Value;
299                 }
300                 serverNtdsaEntry.Properties[PropertyManager.Options].Value = options | 1;
301                 serverNtdsaEntry.CommitChanges();
302             }
303             catch (COMException e)
304             {
305                 throw ExceptionHelper.GetExceptionFromCOMException(context, e);
306             }
307             // return a GlobalCatalog object
308             return new GlobalCatalog(context, Name);
309         }
310 
IsGlobalCatalog()311         public virtual bool IsGlobalCatalog()
312         {
313             CheckIfDisposed();
314 
315             try
316             {
317                 DirectoryEntry serverNtdsaEntry = directoryEntryMgr.GetCachedDirectoryEntry(NtdsaObjectName);
318                 serverNtdsaEntry.RefreshCache();
319                 // check if the NTDSDSA_OPT_IS_GC flag is set in the
320                 // "options" attribute (lowest bit)
321                 int options = 0;
322                 if (serverNtdsaEntry.Properties[PropertyManager.Options].Value != null)
323                 {
324                     options = (int)serverNtdsaEntry.Properties[PropertyManager.Options].Value;
325                 }
326                 if ((options & (1)) == 1)
327                 {
328                     return true;
329                 }
330                 else
331                 {
332                     return false;
333                 }
334             }
335             catch (COMException e)
336             {
337                 throw ExceptionHelper.GetExceptionFromCOMException(context, e);
338             }
339         }
340 
TransferRoleOwnership(ActiveDirectoryRole role)341         public void TransferRoleOwnership(ActiveDirectoryRole role)
342         {
343             CheckIfDisposed();
344 
345             if (role < ActiveDirectoryRole.SchemaRole || role > ActiveDirectoryRole.InfrastructureRole)
346             {
347                 throw new InvalidEnumArgumentException("role", (int)role, typeof(ActiveDirectoryRole));
348             }
349 
350             try
351             {
352                 // set the appropriate attribute on the rootDSE
353                 DirectoryEntry rootDSE = directoryEntryMgr.GetCachedDirectoryEntry(WellKnownDN.RootDSE);
354                 rootDSE.Properties[_becomeRoleOwnerAttrs[(int)role]].Value = 1;
355                 rootDSE.CommitChanges();
356             }
357             catch (COMException e)
358             {
359                 throw ExceptionHelper.GetExceptionFromCOMException(context, e); ;
360             }
361 
362             // invalidate the role collection so that it gets loaded again next time
363             _cachedRoles = null;
364         }
365 
SeizeRoleOwnership(ActiveDirectoryRole role)366         public void SeizeRoleOwnership(ActiveDirectoryRole role)
367         {
368             // set the "fsmoRoleOwner" attribute on the appropriate role object
369             // to the NTDSAObjectName of this DC
370             string roleObjectDN = null;
371 
372             CheckIfDisposed();
373 
374             switch (role)
375             {
376                 case ActiveDirectoryRole.SchemaRole:
377                     {
378                         roleObjectDN = directoryEntryMgr.ExpandWellKnownDN(WellKnownDN.SchemaNamingContext);
379                         break;
380                     }
381                 case ActiveDirectoryRole.NamingRole:
382                     {
383                         roleObjectDN = directoryEntryMgr.ExpandWellKnownDN(WellKnownDN.PartitionsContainer);
384                         break;
385                     }
386                 case ActiveDirectoryRole.PdcRole:
387                     {
388                         roleObjectDN = directoryEntryMgr.ExpandWellKnownDN(WellKnownDN.DefaultNamingContext);
389                         break;
390                     }
391                 case ActiveDirectoryRole.RidRole:
392                     {
393                         roleObjectDN = directoryEntryMgr.ExpandWellKnownDN(WellKnownDN.RidManager);
394                         break;
395                     }
396                 case ActiveDirectoryRole.InfrastructureRole:
397                     {
398                         roleObjectDN = directoryEntryMgr.ExpandWellKnownDN(WellKnownDN.Infrastructure);
399                         break;
400                     }
401                 default:
402                     throw new InvalidEnumArgumentException("role", (int)role, typeof(ActiveDirectoryRole));
403             }
404 
405             DirectoryEntry roleObjectEntry = null;
406             try
407             {
408                 roleObjectEntry = DirectoryEntryManager.GetDirectoryEntry(context, roleObjectDN);
409 
410                 // For RID FSMO role
411                 // Increment the RIDAvailablePool by 30k.
412                 if (role == ActiveDirectoryRole.RidRole)
413                 {
414                     System.DirectoryServices.Interop.UnsafeNativeMethods.IADsLargeInteger ridPool = (System.DirectoryServices.Interop.UnsafeNativeMethods.IADsLargeInteger)roleObjectEntry.Properties[PropertyManager.RIDAvailablePool].Value;
415 
416                     // check the overflow of the low part
417                     if (ridPool.LowPart + UpdateRidPoolSeizureValue < ridPool.LowPart)
418                     {
419                         throw new InvalidOperationException(SR.UpdateAvailableRIDPoolOverflowFailure);
420                     }
421                     ridPool.LowPart += UpdateRidPoolSeizureValue;
422                     roleObjectEntry.Properties[PropertyManager.RIDAvailablePool].Value = ridPool;
423                 }
424                 roleObjectEntry.Properties[PropertyManager.FsmoRoleOwner].Value = NtdsaObjectName;
425                 roleObjectEntry.CommitChanges();
426             }
427             catch (COMException e)
428             {
429                 throw ExceptionHelper.GetExceptionFromCOMException(context, e);
430             }
431             finally
432             {
433                 if (roleObjectEntry != null)
434                 {
435                     roleObjectEntry.Dispose();
436                 }
437             }
438 
439             // invalidate the role collection so that it gets loaded again next time
440             _cachedRoles = null;
441         }
442 
GetDirectorySearcher()443         public virtual DirectorySearcher GetDirectorySearcher()
444         {
445             CheckIfDisposed();
446 
447             return InternalGetDirectorySearcher();
448         }
449 
CheckReplicationConsistency()450         public override void CheckReplicationConsistency()
451         {
452             if (_disposed)
453                 throw new ObjectDisposedException(GetType().Name);
454 
455             // get the handle
456             GetDSHandle();
457 
458             // call private helper function
459             CheckConsistencyHelper(_dsHandle, DirectoryContext.ADHandle);
460         }
461 
GetReplicationCursors(string partition)462         public override ReplicationCursorCollection GetReplicationCursors(string partition)
463         {
464             IntPtr info = (IntPtr)0;
465             int context = 0;
466             bool advanced = true;
467 
468             if (_disposed)
469                 throw new ObjectDisposedException(GetType().Name);
470 
471             if (partition == null)
472                 throw new ArgumentNullException("partition");
473 
474             if (partition.Length == 0)
475                 throw new ArgumentException(SR.EmptyStringParameter, "partition");
476 
477             // get the handle
478             GetDSHandle();
479             info = GetReplicationInfoHelper(_dsHandle, (int)DS_REPL_INFO_TYPE.DS_REPL_INFO_CURSORS_3_FOR_NC, (int)DS_REPL_INFO_TYPE.DS_REPL_INFO_CURSORS_FOR_NC, partition, ref advanced, context, DirectoryContext.ADHandle);
480             return ConstructReplicationCursors(_dsHandle, advanced, info, partition, this, DirectoryContext.ADHandle);
481         }
482 
GetReplicationOperationInformation()483         public override ReplicationOperationInformation GetReplicationOperationInformation()
484         {
485             IntPtr info = (IntPtr)0;
486             bool advanced = true;
487 
488             if (_disposed)
489                 throw new ObjectDisposedException(GetType().Name);
490 
491             // get the handle
492             GetDSHandle();
493             info = GetReplicationInfoHelper(_dsHandle, (int)DS_REPL_INFO_TYPE.DS_REPL_INFO_PENDING_OPS, (int)DS_REPL_INFO_TYPE.DS_REPL_INFO_PENDING_OPS, null, ref advanced, 0, DirectoryContext.ADHandle);
494             return ConstructPendingOperations(info, this, DirectoryContext.ADHandle);
495         }
496 
GetReplicationNeighbors(string partition)497         public override ReplicationNeighborCollection GetReplicationNeighbors(string partition)
498         {
499             IntPtr info = (IntPtr)0;
500             bool advanced = true;
501 
502             if (_disposed)
503                 throw new ObjectDisposedException(GetType().Name);
504 
505             if (partition == null)
506                 throw new ArgumentNullException("partition");
507 
508             if (partition.Length == 0)
509                 throw new ArgumentException(SR.EmptyStringParameter, "partition");
510 
511             // get the handle
512             GetDSHandle();
513             info = GetReplicationInfoHelper(_dsHandle, (int)DS_REPL_INFO_TYPE.DS_REPL_INFO_NEIGHBORS, (int)DS_REPL_INFO_TYPE.DS_REPL_INFO_NEIGHBORS, partition, ref advanced, 0, DirectoryContext.ADHandle);
514             return ConstructNeighbors(info, this, DirectoryContext.ADHandle);
515         }
516 
GetAllReplicationNeighbors()517         public override ReplicationNeighborCollection GetAllReplicationNeighbors()
518         {
519             IntPtr info = (IntPtr)0;
520             bool advanced = true;
521 
522             if (_disposed)
523                 throw new ObjectDisposedException(GetType().Name);
524 
525             // get the handle
526             GetDSHandle();
527             info = GetReplicationInfoHelper(_dsHandle, (int)DS_REPL_INFO_TYPE.DS_REPL_INFO_NEIGHBORS, (int)DS_REPL_INFO_TYPE.DS_REPL_INFO_NEIGHBORS, null, ref advanced, 0, DirectoryContext.ADHandle);
528             return ConstructNeighbors(info, this, DirectoryContext.ADHandle);
529         }
530 
GetReplicationConnectionFailures()531         public override ReplicationFailureCollection GetReplicationConnectionFailures()
532         {
533             return GetReplicationFailures(DS_REPL_INFO_TYPE.DS_REPL_INFO_KCC_DSA_CONNECT_FAILURES);
534         }
535 
GetReplicationMetadata(string objectPath)536         public override ActiveDirectoryReplicationMetadata GetReplicationMetadata(string objectPath)
537         {
538             IntPtr info = (IntPtr)0;
539             bool advanced = true;
540 
541             if (_disposed)
542                 throw new ObjectDisposedException(GetType().Name);
543 
544             if (objectPath == null)
545                 throw new ArgumentNullException("objectPath");
546 
547             if (objectPath.Length == 0)
548                 throw new ArgumentException(SR.EmptyStringParameter, "objectPath");
549 
550             // get the handle
551             GetDSHandle();
552             info = GetReplicationInfoHelper(_dsHandle, (int)DS_REPL_INFO_TYPE.DS_REPL_INFO_METADATA_2_FOR_OBJ, (int)DS_REPL_INFO_TYPE.DS_REPL_INFO_METADATA_FOR_OBJ, objectPath, ref advanced, 0, DirectoryContext.ADHandle);
553             return ConstructMetaData(advanced, info, this, DirectoryContext.ADHandle);
554         }
555 
SyncReplicaFromServer(string partition, string sourceServer)556         public override void SyncReplicaFromServer(string partition, string sourceServer)
557         {
558             if (_disposed)
559                 throw new ObjectDisposedException(GetType().Name);
560 
561             if (partition == null)
562                 throw new ArgumentNullException("partition");
563 
564             if (partition.Length == 0)
565                 throw new ArgumentException(SR.EmptyStringParameter, "partition");
566 
567             if (sourceServer == null)
568                 throw new ArgumentNullException("sourceServer");
569 
570             if (sourceServer.Length == 0)
571                 throw new ArgumentException(SR.EmptyStringParameter, "sourceServer");
572 
573             // get the dsHandle
574             GetDSHandle();
575             SyncReplicaHelper(_dsHandle, false, partition, sourceServer, 0, DirectoryContext.ADHandle);
576         }
577 
TriggerSyncReplicaFromNeighbors(string partition)578         public override void TriggerSyncReplicaFromNeighbors(string partition)
579         {
580             if (_disposed)
581                 throw new ObjectDisposedException(GetType().Name);
582 
583             if (partition == null)
584                 throw new ArgumentNullException("partition");
585 
586             if (partition.Length == 0)
587                 throw new ArgumentException(SR.EmptyStringParameter, "partition");
588 
589             // get the dsHandle
590             GetDSHandle();
591             SyncReplicaHelper(_dsHandle, false, partition, null, DS_REPSYNC_ASYNCHRONOUS_OPERATION | DS_REPSYNC_ALL_SOURCES, DirectoryContext.ADHandle);
592         }
593 
SyncReplicaFromAllServers(string partition, SyncFromAllServersOptions options)594         public override void SyncReplicaFromAllServers(string partition, SyncFromAllServersOptions options)
595         {
596             if (_disposed)
597                 throw new ObjectDisposedException(GetType().Name);
598 
599             if (partition == null)
600                 throw new ArgumentNullException("partition");
601 
602             if (partition.Length == 0)
603                 throw new ArgumentException(SR.EmptyStringParameter, "partition");
604 
605             // get the dsHandle
606             GetDSHandle();
607             SyncReplicaAllHelper(_dsHandle, syncAllFunctionPointer, partition, options, SyncFromAllServersCallback, DirectoryContext.ADHandle);
608         }
609         #endregion public methods
610 
611         #region public properties
612 
613         public Forest Forest
614         {
615             get
616             {
617                 CheckIfDisposed();
618                 if (_currentForest == null)
619                 {
620                     DirectoryContext forestContext = Utils.GetNewDirectoryContext(Name, DirectoryContextType.DirectoryServer, context);
621                     _currentForest = Forest.GetForest(forestContext);
622                 }
623                 return _currentForest;
624             }
625         }
626 
627         public DateTime CurrentTime
628         {
629             get
630             {
631                 CheckIfDisposed();
632 
633                 DirectoryEntry rootDSE = DirectoryEntryManager.GetDirectoryEntry(context, WellKnownDN.RootDSE);
634                 string serverUTCTime = null;
635 
636                 try
637                 {
638                     serverUTCTime = (string)PropertyManager.GetPropertyValue(context, rootDSE, PropertyManager.CurrentTime);
639                 }
640                 finally
641                 {
642                     rootDSE.Dispose();
643                 }
644                 return ParseDateTime(serverUTCTime);
645             }
646         }
647 
648         public Int64 HighestCommittedUsn
649         {
650             get
651             {
652                 CheckIfDisposed();
653 
654                 DirectoryEntry rootDSE = DirectoryEntryManager.GetDirectoryEntry(context, WellKnownDN.RootDSE);
655                 string serverHighestCommittedUsn = null;
656 
657                 try
658                 {
659                     serverHighestCommittedUsn = (string)PropertyManager.GetPropertyValue(context, rootDSE, PropertyManager.HighestCommittedUSN);
660                 }
661                 finally
662                 {
663                     rootDSE.Dispose();
664                 }
665                 return Int64.Parse(serverHighestCommittedUsn, NumberFormatInfo.InvariantInfo);
666             }
667         }
668 
669         public string OSVersion
670         {
671             get
672             {
673                 CheckIfDisposed();
674                 if (_cachedOSVersion == null)
675                 {
676                     // get the operating system version attribute
677                     DirectoryEntry computerEntry = directoryEntryMgr.GetCachedDirectoryEntry(ComputerObjectName);
678                     // is in the form Windows Server 2003
679                     _cachedOSVersion = (string)PropertyManager.GetPropertyValue(context, computerEntry, PropertyManager.OperatingSystem);
680                 }
681                 return _cachedOSVersion;
682             }
683         }
684 
685         internal double NumericOSVersion
686         {
687             get
688             {
689                 CheckIfDisposed();
690                 if (_cachedNumericOSVersion == 0)
691                 {
692                     // get the operating system version attribute
693                     DirectoryEntry computerEntry = directoryEntryMgr.GetCachedDirectoryEntry(ComputerObjectName);
694 
695                     // is in the form Windows Server 2003
696                     string osVersion = (string)PropertyManager.GetPropertyValue(context, computerEntry, PropertyManager.OperatingSystemVersion);
697 
698                     // this could be in the form 5.2 (3790), so we need to take out the (3790)
699                     int index = osVersion.IndexOf('(');
700                     if (index != -1)
701                     {
702                         osVersion = osVersion.Substring(0, index);
703                     }
704                     _cachedNumericOSVersion = (double)Double.Parse(osVersion, NumberFormatInfo.InvariantInfo);
705                 }
706 
707                 return _cachedNumericOSVersion;
708             }
709         }
710 
711         public ActiveDirectoryRoleCollection Roles
712         {
713             get
714             {
715                 CheckIfDisposed();
716                 if (_cachedRoles == null)
717                 {
718                     _cachedRoles = new ActiveDirectoryRoleCollection(GetRoles());
719                 }
720                 return _cachedRoles;
721             }
722         }
723 
724         public Domain Domain
725         {
726             get
727             {
728                 CheckIfDisposed();
729                 if (_cachedDomain == null)
730                 {
731                     string domainName = null;
732                     try
733                     {
734                         string defaultNCName = directoryEntryMgr.ExpandWellKnownDN(WellKnownDN.DefaultNamingContext);
735                         domainName = Utils.GetDnsNameFromDN(defaultNCName);
736                     }
737                     catch (COMException e)
738                     {
739                         throw ExceptionHelper.GetExceptionFromCOMException(context, e);
740                     }
741                     // For domain controllers this is always the
742                     // domain naming context
743                     // create a new domain context for the domain
744                     DirectoryContext domainContext = Utils.GetNewDirectoryContext(Name, DirectoryContextType.DirectoryServer, context);
745                     _cachedDomain = new Domain(domainContext, domainName);
746                 }
747                 return _cachedDomain;
748             }
749         }
750 
751         public override string IPAddress
752         {
753             get
754             {
755                 CheckIfDisposed();
756 
757                 IPHostEntry hostEntry = Dns.GetHostEntry(Name);
758                 if (hostEntry.AddressList.GetLength(0) > 0)
759                 {
760                     return (hostEntry.AddressList[0]).ToString();
761                 }
762                 else
763                 {
764                     return null;
765                 }
766             }
767         }
768 
769         public override String SiteName
770         {
771             get
772             {
773                 CheckIfDisposed();
774                 if (!_dcInfoInitialized || siteInfoModified)
775                 {
776                     GetDomainControllerInfo();
777                 }
778                 if (cachedSiteName == null)
779                 {
780                     throw new ActiveDirectoryOperationException(SR.Format(SR.SiteNameNotFound , Name));
781                 }
782 
783                 return cachedSiteName;
784             }
785         }
786 
787         internal String SiteObjectName
788         {
789             get
790             {
791                 CheckIfDisposed();
792                 if (!_dcInfoInitialized || siteInfoModified)
793                 {
794                     GetDomainControllerInfo();
795                 }
796                 if (cachedSiteObjectName == null)
797                 {
798                     throw new ActiveDirectoryOperationException(SR.Format(SR.SiteObjectNameNotFound , Name));
799                 }
800                 return cachedSiteObjectName;
801             }
802         }
803 
804         internal String ComputerObjectName
805         {
806             get
807             {
808                 CheckIfDisposed();
809                 if (!_dcInfoInitialized)
810                 {
811                     GetDomainControllerInfo();
812                 }
813                 if (_cachedComputerObjectName == null)
814                 {
815                     throw new ActiveDirectoryOperationException(SR.Format(SR.ComputerObjectNameNotFound , Name));
816                 }
817                 return _cachedComputerObjectName;
818             }
819         }
820 
821         internal String ServerObjectName
822         {
823             get
824             {
825                 CheckIfDisposed();
826                 if (!_dcInfoInitialized || siteInfoModified)
827                 {
828                     GetDomainControllerInfo();
829                 }
830                 if (cachedServerObjectName == null)
831                 {
832                     throw new ActiveDirectoryOperationException(SR.Format(SR.ServerObjectNameNotFound , Name));
833                 }
834                 return cachedServerObjectName;
835             }
836         }
837 
838         internal String NtdsaObjectName
839         {
840             get
841             {
842                 CheckIfDisposed();
843                 if (!_dcInfoInitialized || siteInfoModified)
844                 {
845                     GetDomainControllerInfo();
846                 }
847                 if (cachedNtdsaObjectName == null)
848                 {
849                     throw new ActiveDirectoryOperationException(SR.Format(SR.NtdsaObjectNameNotFound , Name));
850                 }
851                 return cachedNtdsaObjectName;
852             }
853         }
854 
855         internal Guid NtdsaObjectGuid
856         {
857             get
858             {
859                 CheckIfDisposed();
860                 if (!_dcInfoInitialized || siteInfoModified)
861                 {
862                     GetDomainControllerInfo();
863                 }
864                 if (cachedNtdsaObjectGuid.Equals(Guid.Empty))
865                 {
866                     throw new ActiveDirectoryOperationException(SR.Format(SR.NtdsaObjectGuidNotFound , Name));
867                 }
868                 return cachedNtdsaObjectGuid;
869             }
870         }
871 
872         public override SyncUpdateCallback SyncFromAllServersCallback
873         {
874             get
875             {
876                 if (_disposed)
877                     throw new ObjectDisposedException(GetType().Name);
878 
879                 return userDelegate;
880             }
881 
882             set
883             {
884                 if (_disposed)
885                     throw new ObjectDisposedException(GetType().Name);
886 
887                 userDelegate = value;
888             }
889         }
890 
891         public override ReplicationConnectionCollection InboundConnections => GetInboundConnectionsHelper();
892 
893         public override ReplicationConnectionCollection OutboundConnections => GetOutboundConnectionsHelper();
894 
895         internal IntPtr Handle
896         {
897             get
898             {
899                 GetDSHandle();
900                 return _dsHandle;
901             }
902         }
903 
904         #endregion public properties
905 
906         #region private methods
907 
ValidateCredential(DomainController dc, DirectoryContext context)908         internal static void ValidateCredential(DomainController dc, DirectoryContext context)
909         {
910             DirectoryEntry de;
911 
912             de = new DirectoryEntry("LDAP://" + dc.Name + "/RootDSE", context.UserName, context.Password, Utils.DefaultAuthType | AuthenticationTypes.ServerBind);
913 
914             de.Bind(true);
915         }
916 
FindOneWithCredentialValidation(DirectoryContext context, string siteName, LocatorOptions flag)917         internal static DomainController FindOneWithCredentialValidation(DirectoryContext context, string siteName, LocatorOptions flag)
918         {
919             DomainController dc;
920             bool retry = false;
921             bool credsValidated = false;
922 
923             //  work with copy of the context
924             context = new DirectoryContext(context);
925 
926             // authenticate against this DC to validate the credentials
927             dc = FindOneInternal(context, context.Name, siteName, flag);
928             try
929             {
930                 ValidateCredential(dc, context);
931                 credsValidated = true;
932             }
933             catch (COMException e)
934             {
935                 if (e.ErrorCode == unchecked((int)0x8007203a))
936                 {
937                     // server is down , so try again with force rediscovery if the flags did not already contain force rediscovery
938                     if ((flag & LocatorOptions.ForceRediscovery) == 0)
939                     {
940                         retry = true;
941                     }
942                     else
943                     {
944                         throw new ActiveDirectoryObjectNotFoundException(SR.Format(SR.DCNotFoundInDomain , context.Name), typeof(DomainController), null);
945                     }
946                 }
947                 else
948                 {
949                     throw ExceptionHelper.GetExceptionFromCOMException(context, e);
950                 }
951             }
952             finally
953             {
954                 if (!credsValidated)
955                 {
956                     dc.Dispose();
957                 }
958             }
959 
960             if (retry)
961             {
962                 credsValidated = false;
963                 dc = FindOneInternal(context, context.Name, siteName, flag | LocatorOptions.ForceRediscovery);
964                 try
965                 {
966                     ValidateCredential(dc, context);
967                     credsValidated = true;
968                 }
969                 catch (COMException e)
970                 {
971                     if (e.ErrorCode == unchecked((int)0x8007203a))
972                     {
973                         // server is down
974                         throw new ActiveDirectoryObjectNotFoundException(SR.Format(SR.DCNotFoundInDomain , context.Name), typeof(DomainController), null);
975                     }
976                     else
977                     {
978                         throw ExceptionHelper.GetExceptionFromCOMException(context, e);
979                     }
980                 }
981                 finally
982                 {
983                     if (!credsValidated)
984                     {
985                         dc.Dispose();
986                     }
987                 }
988             }
989 
990             return dc;
991         }
992 
FindOneInternal(DirectoryContext context, string domainName, string siteName, LocatorOptions flag)993         internal static DomainController FindOneInternal(DirectoryContext context, string domainName, string siteName, LocatorOptions flag)
994         {
995             DomainControllerInfo domainControllerInfo;
996             int errorCode = 0;
997 
998             if (siteName != null && siteName.Length == 0)
999             {
1000                 throw new ArgumentException(SR.EmptyStringParameter, "siteName");
1001             }
1002 
1003             // check that the flags passed have only the valid bits set
1004             if (((long)flag & (~((long)LocatorOptions.AvoidSelf | (long)LocatorOptions.ForceRediscovery | (long)LocatorOptions.KdcRequired | (long)LocatorOptions.TimeServerRequired | (long)LocatorOptions.WriteableRequired))) != 0)
1005             {
1006                 throw new ArgumentException(SR.InvalidFlags, "flag");
1007             }
1008 
1009             if (domainName == null)
1010             {
1011                 domainName = DirectoryContext.GetLoggedOnDomain();
1012             }
1013 
1014             // call DsGetDcName
1015             errorCode = Locator.DsGetDcNameWrapper(null, domainName, siteName, (long)flag | (long)PrivateLocatorFlags.DirectoryServicesRequired, out domainControllerInfo);
1016 
1017             if (errorCode == NativeMethods.ERROR_NO_SUCH_DOMAIN)
1018             {
1019                 throw new ActiveDirectoryObjectNotFoundException(SR.Format(SR.DCNotFoundInDomain , domainName), typeof(DomainController), null);
1020             }
1021             // this can only occur when flag is being explicitly passed (since the flags that we pass internally are valid)
1022             if (errorCode == NativeMethods.ERROR_INVALID_FLAGS)
1023             {
1024                 throw new ArgumentException(SR.InvalidFlags, "flag");
1025             }
1026             else if (errorCode != 0)
1027             {
1028                 throw ExceptionHelper.GetExceptionFromErrorCode(errorCode);
1029             }
1030 
1031             // create a DomainController object
1032             Debug.Assert(domainControllerInfo.DomainControllerName.Length > 2);
1033             string domainControllerName = domainControllerInfo.DomainControllerName.Substring(2);
1034 
1035             // create a new context object for the domain controller
1036             DirectoryContext dcContext = Utils.GetNewDirectoryContext(domainControllerName, DirectoryContextType.DirectoryServer, context);
1037 
1038             return new DomainController(dcContext, domainControllerName);
1039         }
1040 
FindAllInternal(DirectoryContext context, string domainName, bool isDnsDomainName, string siteName)1041         internal static DomainControllerCollection FindAllInternal(DirectoryContext context, string domainName, bool isDnsDomainName, string siteName)
1042         {
1043             ArrayList dcList = new ArrayList();
1044 
1045             if (siteName != null && siteName.Length == 0)
1046             {
1047                 throw new ArgumentException(SR.EmptyStringParameter, "siteName");
1048             }
1049 
1050             if (domainName == null || !isDnsDomainName)
1051             {
1052                 // get the dns name of the domain
1053                 DomainControllerInfo domainControllerInfo;
1054                 int errorCode = Locator.DsGetDcNameWrapper(null, (domainName != null) ? domainName : DirectoryContext.GetLoggedOnDomain(), null, (long)PrivateLocatorFlags.DirectoryServicesRequired, out domainControllerInfo);
1055 
1056                 if (errorCode == NativeMethods.ERROR_NO_SUCH_DOMAIN)
1057                 {
1058                     // return an empty collection
1059                     return new DomainControllerCollection(dcList);
1060                 }
1061                 else if (errorCode != 0)
1062                 {
1063                     throw ExceptionHelper.GetExceptionFromErrorCode(errorCode);
1064                 }
1065 
1066                 Debug.Assert(domainControllerInfo.DomainName != null);
1067                 domainName = domainControllerInfo.DomainName;
1068             }
1069 
1070             foreach (string dcName in Utils.GetReplicaList(context, Utils.GetDNFromDnsName(domainName), siteName, true /* isDefaultNC */, false /* isADAM */, false /* mustBeGC */))
1071             {
1072                 DirectoryContext dcContext = Utils.GetNewDirectoryContext(dcName, DirectoryContextType.DirectoryServer, context);
1073                 dcList.Add(new DomainController(dcContext, dcName));
1074             }
1075 
1076             return new DomainControllerCollection(dcList);
1077         }
1078 
GetDomainControllerInfo()1079         private void GetDomainControllerInfo()
1080         {
1081             int result = 0;
1082             int dcCount = 0;
1083             IntPtr dcInfoPtr = IntPtr.Zero;
1084             int dcInfoLevel = 0;
1085             bool initialized = false;
1086 
1087             // get the handle
1088             GetDSHandle();
1089 
1090             // call DsGetDomainControllerInfo
1091             IntPtr functionPtr = UnsafeNativeMethods.GetProcAddress(DirectoryContext.ADHandle, "DsGetDomainControllerInfoW");
1092             if (functionPtr == (IntPtr)0)
1093             {
1094                 throw ExceptionHelper.GetExceptionFromErrorCode(Marshal.GetLastWin32Error());
1095             }
1096             NativeMethods.DsGetDomainControllerInfo dsGetDomainControllerInfo = (NativeMethods.DsGetDomainControllerInfo)Marshal.GetDelegateForFunctionPointer(functionPtr, typeof(NativeMethods.DsGetDomainControllerInfo));
1097 
1098             // try DsDomainControllerInfoLevel3 first which supports Read only DC (RODC)
1099             dcInfoLevel = NativeMethods.DsDomainControllerInfoLevel3;
1100             result = dsGetDomainControllerInfo(_dsHandle, Domain.Name, dcInfoLevel, out dcCount, out dcInfoPtr);
1101 
1102             if (result != 0)
1103             {
1104                 // fallback to DsDomainControllerInfoLevel2
1105                 dcInfoLevel = NativeMethods.DsDomainControllerInfoLevel2;
1106                 result = dsGetDomainControllerInfo(_dsHandle, Domain.Name, dcInfoLevel, out dcCount, out dcInfoPtr);
1107             }
1108 
1109             if (result == 0)
1110             {
1111                 try
1112                 {
1113                     IntPtr currentDc = dcInfoPtr;
1114                     for (int i = 0; i < dcCount; i++)
1115                     {
1116                         if (dcInfoLevel == NativeMethods.DsDomainControllerInfoLevel3)
1117                         {
1118                             DsDomainControllerInfo3 domainControllerInfo3 = new DsDomainControllerInfo3();
1119                             Marshal.PtrToStructure(currentDc, domainControllerInfo3);
1120                             // check if this is the same as "this" DC
1121                             if (domainControllerInfo3 != null)
1122                             {
1123                                 if (Utils.Compare(domainControllerInfo3.dnsHostName, replicaName) == 0)
1124                                 {
1125                                     initialized = true;
1126 
1127                                     // update all the fields
1128                                     cachedSiteName = domainControllerInfo3.siteName;
1129                                     cachedSiteObjectName = domainControllerInfo3.siteObjectName;
1130                                     _cachedComputerObjectName = domainControllerInfo3.computerObjectName;
1131                                     cachedServerObjectName = domainControllerInfo3.serverObjectName;
1132                                     cachedNtdsaObjectName = domainControllerInfo3.ntdsaObjectName;
1133                                     cachedNtdsaObjectGuid = domainControllerInfo3.ntdsDsaObjectGuid;
1134                                 }
1135                             }
1136                             currentDc = IntPtr.Add(currentDc, Marshal.SizeOf(domainControllerInfo3));
1137                         }
1138                         else
1139                         { //NativeMethods.DsDomainControllerInfoLevel2
1140                             DsDomainControllerInfo2 domainControllerInfo2 = new DsDomainControllerInfo2();
1141                             Marshal.PtrToStructure(currentDc, domainControllerInfo2);
1142                             // check if this is the same as "this" DC
1143                             if (domainControllerInfo2 != null)
1144                             {
1145                                 if (Utils.Compare(domainControllerInfo2.dnsHostName, replicaName) == 0)
1146                                 {
1147                                     initialized = true;
1148 
1149                                     // update all the fields
1150                                     cachedSiteName = domainControllerInfo2.siteName;
1151                                     cachedSiteObjectName = domainControllerInfo2.siteObjectName;
1152                                     _cachedComputerObjectName = domainControllerInfo2.computerObjectName;
1153                                     cachedServerObjectName = domainControllerInfo2.serverObjectName;
1154                                     cachedNtdsaObjectName = domainControllerInfo2.ntdsaObjectName;
1155                                     cachedNtdsaObjectGuid = domainControllerInfo2.ntdsDsaObjectGuid;
1156                                 }
1157                             }
1158                             currentDc = IntPtr.Add(currentDc, Marshal.SizeOf(domainControllerInfo2));
1159                         }
1160                     }
1161                 }
1162                 finally
1163                 {
1164                     // free the domain controller info structure
1165                     if (dcInfoPtr != IntPtr.Zero)
1166                     {
1167                         // call DsFreeDomainControllerInfo
1168                         functionPtr = UnsafeNativeMethods.GetProcAddress(DirectoryContext.ADHandle, "DsFreeDomainControllerInfoW");
1169                         if (functionPtr == (IntPtr)0)
1170                         {
1171                             throw ExceptionHelper.GetExceptionFromErrorCode(Marshal.GetLastWin32Error());
1172                         }
1173                         NativeMethods.DsFreeDomainControllerInfo dsFreeDomainControllerInfo = (NativeMethods.DsFreeDomainControllerInfo)Marshal.GetDelegateForFunctionPointer(functionPtr, typeof(NativeMethods.DsFreeDomainControllerInfo));
1174                         dsFreeDomainControllerInfo(dcInfoLevel, dcCount, dcInfoPtr);
1175                     }
1176                 }
1177 
1178                 // if we couldn't get this DC's info, throw an exception
1179                 if (!initialized)
1180                 {
1181                     throw new ActiveDirectoryOperationException(SR.DCInfoNotFound);
1182                 }
1183 
1184                 _dcInfoInitialized = true;
1185                 siteInfoModified = false;
1186             }
1187             else
1188             {
1189                 throw ExceptionHelper.GetExceptionFromErrorCode(result, Name);
1190             }
1191         }
1192 
GetDSHandle()1193         internal void GetDSHandle()
1194         {
1195             if (_disposed)
1196             {
1197                 // cannot bind to the domain controller as the object has been
1198                 // disposed (finalizer has been suppressed)
1199                 throw new ObjectDisposedException(GetType().Name);
1200             }
1201 
1202             // this part of the code needs to be synchronized
1203             lock (this)
1204             {
1205                 if (_dsHandle == IntPtr.Zero)
1206                 {
1207                     // get the credentials object
1208                     if (_authIdentity == IntPtr.Zero)
1209                     {
1210                         _authIdentity = Utils.GetAuthIdentity(context, DirectoryContext.ADHandle);
1211                     }
1212 
1213                     // DsBind
1214                     _dsHandle = Utils.GetDSHandle(replicaName, null, _authIdentity, DirectoryContext.ADHandle);
1215                 }
1216             }
1217         }
1218 
FreeDSHandle()1219         internal void FreeDSHandle()
1220         {
1221             lock (this)
1222             {
1223                 // DsUnbind
1224                 Utils.FreeDSHandle(_dsHandle, DirectoryContext.ADHandle);
1225                 // free the credentials object
1226                 Utils.FreeAuthIdentity(_authIdentity, DirectoryContext.ADHandle);
1227             }
1228         }
1229 
GetReplicationFailures(DS_REPL_INFO_TYPE type)1230         internal ReplicationFailureCollection GetReplicationFailures(DS_REPL_INFO_TYPE type)
1231         {
1232             IntPtr info = (IntPtr)0;
1233             bool advanced = true;
1234 
1235             if (_disposed)
1236                 throw new ObjectDisposedException(GetType().Name);
1237 
1238             // get the handle
1239             GetDSHandle();
1240             info = GetReplicationInfoHelper(_dsHandle, (int)type, (int)type, null, ref advanced, 0, DirectoryContext.ADHandle);
1241             return ConstructFailures(info, this, DirectoryContext.ADHandle);
1242         }
1243 
GetRoles()1244         private ArrayList GetRoles()
1245         {
1246             ArrayList roleList = new ArrayList();
1247             int result = 0;
1248             IntPtr rolesPtr = IntPtr.Zero;
1249 
1250             GetDSHandle();
1251             // Get the roles
1252             // call DsListRoles
1253             IntPtr functionPtr = UnsafeNativeMethods.GetProcAddress(DirectoryContext.ADHandle, "DsListRolesW");
1254             if (functionPtr == (IntPtr)0)
1255             {
1256                 throw ExceptionHelper.GetExceptionFromErrorCode(Marshal.GetLastWin32Error());
1257             }
1258             NativeMethods.DsListRoles dsListRoles = (NativeMethods.DsListRoles)Marshal.GetDelegateForFunctionPointer(functionPtr, typeof(NativeMethods.DsListRoles));
1259 
1260             result = dsListRoles(_dsHandle, out rolesPtr);
1261             if (result == 0)
1262             {
1263                 try
1264                 {
1265                     DsNameResult dsNameResult = new DsNameResult();
1266                     Marshal.PtrToStructure(rolesPtr, dsNameResult);
1267                     IntPtr currentItem = dsNameResult.items;
1268                     for (int i = 0; i < dsNameResult.itemCount; i++)
1269                     {
1270                         DsNameResultItem dsNameResultItem = new DsNameResultItem();
1271                         Marshal.PtrToStructure(currentItem, dsNameResultItem);
1272 
1273                         // check if the role owner is this dc
1274                         if (dsNameResultItem.status == NativeMethods.DsNameNoError)
1275                         {
1276                             if (dsNameResultItem.name.Equals(NtdsaObjectName))
1277                             {
1278                                 // add this role to the array
1279                                 // the index of the item in the result signifies
1280                                 // which role owner it is
1281                                 roleList.Add((ActiveDirectoryRole)i);
1282                             }
1283                         }
1284                         currentItem = IntPtr.Add(currentItem, Marshal.SizeOf(dsNameResultItem));
1285                     }
1286                 }
1287                 finally
1288                 {
1289                     // free the DsNameResult structure
1290                     if (rolesPtr != IntPtr.Zero)
1291                     {
1292                         // call DsFreeNameResult
1293                         functionPtr = UnsafeNativeMethods.GetProcAddress(DirectoryContext.ADHandle, "DsFreeNameResultW");
1294                         if (functionPtr == (IntPtr)0)
1295                         {
1296                             throw ExceptionHelper.GetExceptionFromErrorCode(Marshal.GetLastWin32Error());
1297                         }
1298                         UnsafeNativeMethods.DsFreeNameResultW dsFreeNameResult = (UnsafeNativeMethods.DsFreeNameResultW)Marshal.GetDelegateForFunctionPointer(functionPtr, typeof(UnsafeNativeMethods.DsFreeNameResultW));
1299                         dsFreeNameResult(rolesPtr);
1300                     }
1301                 }
1302             }
1303             else
1304             {
1305                 throw ExceptionHelper.GetExceptionFromErrorCode(result, Name);
1306             }
1307             return roleList;
1308         }
1309 
ParseDateTime(string dateTime)1310         private DateTime ParseDateTime(string dateTime)
1311         {
1312             int year = (int)Int32.Parse(dateTime.Substring(0, 4), NumberFormatInfo.InvariantInfo);
1313             int month = (int)Int32.Parse(dateTime.Substring(4, 2), NumberFormatInfo.InvariantInfo);
1314             int day = (int)Int32.Parse(dateTime.Substring(6, 2), NumberFormatInfo.InvariantInfo);
1315             int hour = (int)Int32.Parse(dateTime.Substring(8, 2), NumberFormatInfo.InvariantInfo);
1316             int min = (int)Int32.Parse(dateTime.Substring(10, 2), NumberFormatInfo.InvariantInfo);
1317             int sec = (int)Int32.Parse(dateTime.Substring(12, 2), NumberFormatInfo.InvariantInfo);
1318 
1319             // this is the UniversalTime
1320             return new DateTime(year, month, day, hour, min, sec, 0);
1321         }
1322 
InternalGetDirectorySearcher()1323         private DirectorySearcher InternalGetDirectorySearcher()
1324         {
1325             DirectoryEntry de = new DirectoryEntry("LDAP://" + Name);
1326 
1327             de.AuthenticationType = Utils.DefaultAuthType | AuthenticationTypes.ServerBind;
1328 
1329             de.Username = context.UserName;
1330             de.Password = context.Password;
1331 
1332             return new DirectorySearcher(de);
1333         }
1334         #endregion private methods
1335     }
1336 }
1337