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.Collections; 6 using System.Globalization; 7 using System.Runtime.InteropServices; 8 using System.Diagnostics; 9 10 namespace System.DirectoryServices.ActiveDirectory 11 { 12 public abstract class DirectoryServer : IDisposable 13 { 14 private bool _disposed = false; 15 internal DirectoryContext context = null; 16 internal string replicaName = null; 17 internal DirectoryEntryManager directoryEntryMgr = null; 18 19 // internal variables for the public properties 20 internal bool siteInfoModified = false; 21 internal string cachedSiteName = null; 22 internal string cachedSiteObjectName = null; 23 internal string cachedServerObjectName = null; 24 internal string cachedNtdsaObjectName = null; 25 internal Guid cachedNtdsaObjectGuid = Guid.Empty; 26 // disable csharp compiler warning #0414: field assigned unused value 27 #pragma warning disable 0414 28 internal string cachedIPAddress = null; 29 #pragma warning restore 0414 30 internal ReadOnlyStringCollection cachedPartitions = null; 31 32 internal const int DS_REPSYNC_ASYNCHRONOUS_OPERATION = 0x00000001; 33 internal const int DS_REPSYNC_ALL_SOURCES = 0x00000010; 34 internal const int DS_REPSYNCALL_ID_SERVERS_BY_DN = 0x00000004; 35 internal const int DS_REPL_NOTSUPPORTED = 50; 36 private const int DS_REPL_INFO_FLAG_IMPROVE_LINKED_ATTRS = 0x00000001; 37 private ReplicationConnectionCollection _inbound = null; 38 private ReplicationConnectionCollection _outbound = null; 39 40 #region constructors DirectoryServer()41 protected DirectoryServer() 42 { 43 } 44 #endregion constructors 45 46 #region IDisposable ~DirectoryServer()47 ~DirectoryServer() => Dispose(false); 48 Dispose()49 public void Dispose() 50 { 51 Dispose(true); 52 53 // Take yourself off of the Finalization queue 54 // to prevent finalization code for this object 55 // from executing a second time. 56 GC.SuppressFinalize(this); 57 } 58 59 // private Dispose method Dispose(bool disposing)60 protected virtual void Dispose(bool disposing) 61 { 62 if (!_disposed) 63 { 64 // check if this is an explicit Dispose 65 // only then clean up the directory entries 66 if (disposing) 67 { 68 // dispose all directory entries 69 foreach (DirectoryEntry entry in directoryEntryMgr.GetCachedDirectoryEntries()) 70 { 71 entry.Dispose(); 72 } 73 } 74 _disposed = true; 75 } 76 } 77 #endregion IDisposable 78 79 #region public methods ToString()80 public override string ToString() => Name; 81 MoveToAnotherSite(string siteName)82 public void MoveToAnotherSite(string siteName) 83 { 84 CheckIfDisposed(); 85 86 // validate siteName 87 if (siteName == null) 88 { 89 throw new ArgumentNullException("siteName"); 90 } 91 92 if (siteName.Length == 0) 93 { 94 throw new ArgumentException(SR.EmptyStringParameter, "siteName"); 95 } 96 97 // the dc is really being moved to a different site 98 if (Utils.Compare(SiteName, siteName) != 0) 99 { 100 DirectoryEntry newParentEntry = null; 101 try 102 { 103 // Bind to the target site's server container 104 // Get the distinguished name for the site 105 string parentDN = "CN=Servers,CN=" + siteName + "," + directoryEntryMgr.ExpandWellKnownDN(WellKnownDN.SitesContainer); 106 newParentEntry = DirectoryEntryManager.GetDirectoryEntry(context, parentDN); 107 108 string serverName = (this is DomainController) ? ((DomainController)this).ServerObjectName : ((AdamInstance)this).ServerObjectName; 109 110 DirectoryEntry serverEntry = directoryEntryMgr.GetCachedDirectoryEntry(serverName); 111 112 // force binding (needed otherwise S.DS throw an exception while releasing the COM interface pointer) 113 string dn = (string)PropertyManager.GetPropertyValue(context, serverEntry, PropertyManager.DistinguishedName); 114 115 // move the object to the servers container of the target site 116 serverEntry.MoveTo(newParentEntry); 117 } 118 catch (COMException e) 119 { 120 throw ExceptionHelper.GetExceptionFromCOMException(context, e); 121 } 122 finally 123 { 124 if (newParentEntry != null) 125 { 126 newParentEntry.Dispose(); 127 } 128 } 129 130 // remove stale cached directory entries 131 // invalidate the cached properties that get affected by this 132 siteInfoModified = true; 133 cachedSiteName = null; 134 135 if (cachedSiteObjectName != null) 136 { 137 directoryEntryMgr.RemoveIfExists(cachedSiteObjectName); 138 cachedSiteObjectName = null; 139 } 140 141 if (cachedServerObjectName != null) 142 { 143 directoryEntryMgr.RemoveIfExists(cachedServerObjectName); 144 cachedServerObjectName = null; 145 } 146 147 if (cachedNtdsaObjectName != null) 148 { 149 directoryEntryMgr.RemoveIfExists(cachedNtdsaObjectName); 150 cachedNtdsaObjectName = null; 151 } 152 } 153 } 154 GetDirectoryEntry()155 public DirectoryEntry GetDirectoryEntry() 156 { 157 CheckIfDisposed(); 158 string serverName = (this is DomainController) ? ((DomainController)this).ServerObjectName : ((AdamInstance)this).ServerObjectName; 159 return DirectoryEntryManager.GetDirectoryEntry(context, serverName); 160 } 161 162 #endregion public methods 163 164 #region abstract public methods 165 CheckReplicationConsistency()166 public abstract void CheckReplicationConsistency(); 167 GetReplicationCursors(string partition)168 public abstract ReplicationCursorCollection GetReplicationCursors(string partition); 169 GetReplicationOperationInformation()170 public abstract ReplicationOperationInformation GetReplicationOperationInformation(); 171 GetReplicationNeighbors(string partition)172 public abstract ReplicationNeighborCollection GetReplicationNeighbors(string partition); 173 GetAllReplicationNeighbors()174 public abstract ReplicationNeighborCollection GetAllReplicationNeighbors(); 175 GetReplicationConnectionFailures()176 public abstract ReplicationFailureCollection GetReplicationConnectionFailures(); 177 GetReplicationMetadata(string objectPath)178 public abstract ActiveDirectoryReplicationMetadata GetReplicationMetadata(string objectPath); 179 SyncReplicaFromServer(string partition, string sourceServer)180 public abstract void SyncReplicaFromServer(string partition, string sourceServer); 181 TriggerSyncReplicaFromNeighbors(string partition)182 public abstract void TriggerSyncReplicaFromNeighbors(string partition); 183 SyncReplicaFromAllServers(string partition, SyncFromAllServersOptions options)184 public abstract void SyncReplicaFromAllServers(string partition, SyncFromAllServersOptions options); 185 186 #endregion abstract public methods 187 188 #region public properties 189 190 public string Name 191 { 192 get 193 { 194 CheckIfDisposed(); 195 return replicaName; 196 } 197 } 198 199 public ReadOnlyStringCollection Partitions 200 { 201 get 202 { 203 CheckIfDisposed(); 204 if (cachedPartitions == null) 205 { 206 cachedPartitions = new ReadOnlyStringCollection(GetPartitions()); 207 } 208 return cachedPartitions; 209 } 210 } 211 212 #endregion public properties 213 214 #region abstract public properties 215 216 public abstract string IPAddress { get; } 217 218 public abstract string SiteName { get; } 219 220 public abstract SyncUpdateCallback SyncFromAllServersCallback { get; set; } 221 222 public abstract ReplicationConnectionCollection InboundConnections { get; } 223 224 public abstract ReplicationConnectionCollection OutboundConnections { get; } 225 226 #endregion abstract public properties 227 228 #region private methods 229 GetPartitions()230 internal ArrayList GetPartitions() 231 { 232 ArrayList partitionList = new ArrayList(); 233 DirectoryEntry rootDSE = null; 234 DirectoryEntry serverNtdsaEntry = null; 235 236 try 237 { 238 // get the writable partitions 239 rootDSE = DirectoryEntryManager.GetDirectoryEntry(context, WellKnownDN.RootDSE); 240 // don't need range retrieval for root dse attributes 241 foreach (string partition in rootDSE.Properties[PropertyManager.NamingContexts]) 242 { 243 partitionList.Add(partition); 244 } 245 246 // also the read only partitions 247 string ntdsaName = (this is DomainController) ? ((DomainController)this).NtdsaObjectName : ((AdamInstance)this).NtdsaObjectName; 248 serverNtdsaEntry = DirectoryEntryManager.GetDirectoryEntry(context, ntdsaName); 249 250 // use range retrieval 251 ArrayList propertyNames = new ArrayList(); 252 propertyNames.Add(PropertyManager.HasPartialReplicaNCs); 253 254 Hashtable values = null; 255 try 256 { 257 values = Utils.GetValuesWithRangeRetrieval(serverNtdsaEntry, null, propertyNames, SearchScope.Base); 258 } 259 catch (COMException e) 260 { 261 throw ExceptionHelper.GetExceptionFromCOMException(context, e); 262 } 263 264 ArrayList readOnlyPartitions = (ArrayList)values[PropertyManager.HasPartialReplicaNCs.ToLower(CultureInfo.InvariantCulture)]; 265 266 Debug.Assert(readOnlyPartitions != null); 267 foreach (string readOnlyPartition in readOnlyPartitions) 268 { 269 partitionList.Add(readOnlyPartition); 270 } 271 } 272 catch (COMException e) 273 { 274 throw ExceptionHelper.GetExceptionFromCOMException(context, e); 275 } 276 finally 277 { 278 if (rootDSE != null) 279 { 280 rootDSE.Dispose(); 281 } 282 283 if (serverNtdsaEntry != null) 284 { 285 serverNtdsaEntry.Dispose(); 286 } 287 } 288 return partitionList; 289 } 290 CheckIfDisposed()291 internal void CheckIfDisposed() 292 { 293 if (_disposed) 294 { 295 throw new ObjectDisposedException(GetType().Name); 296 } 297 } 298 299 internal DirectoryContext Context => context; 300 CheckConsistencyHelper(IntPtr dsHandle, LoadLibrarySafeHandle libHandle)301 internal void CheckConsistencyHelper(IntPtr dsHandle, LoadLibrarySafeHandle libHandle) 302 { 303 // call DsReplicaConsistencyCheck 304 IntPtr functionPtr = UnsafeNativeMethods.GetProcAddress(libHandle, "DsReplicaConsistencyCheck"); 305 if (functionPtr == (IntPtr)0) 306 { 307 throw ExceptionHelper.GetExceptionFromErrorCode(Marshal.GetLastWin32Error()); 308 } 309 UnsafeNativeMethods.DsReplicaConsistencyCheck replicaConsistencyCheck = (UnsafeNativeMethods.DsReplicaConsistencyCheck)Marshal.GetDelegateForFunctionPointer(functionPtr, typeof(UnsafeNativeMethods.DsReplicaConsistencyCheck)); 310 311 int result = replicaConsistencyCheck(dsHandle, 0, 0); 312 313 if (result != 0) 314 throw ExceptionHelper.GetExceptionFromErrorCode(result, Name); 315 } 316 GetReplicationInfoHelper(IntPtr dsHandle, int type, int secondaryType, string partition, ref bool advanced, int context, LoadLibrarySafeHandle libHandle)317 internal IntPtr GetReplicationInfoHelper(IntPtr dsHandle, int type, int secondaryType, string partition, ref bool advanced, int context, LoadLibrarySafeHandle libHandle) 318 { 319 IntPtr info = (IntPtr)0; 320 int result = 0; 321 bool needToTryAgain = true; 322 IntPtr functionPtr; 323 324 // first try to use the DsReplicaGetInfo2W API which does not exist on win2k machine 325 // call DsReplicaGetInfo2W 326 functionPtr = UnsafeNativeMethods.GetProcAddress(libHandle, "DsReplicaGetInfo2W"); 327 if (functionPtr == (IntPtr)0) 328 { 329 // a win2k machine which does not have it. 330 functionPtr = UnsafeNativeMethods.GetProcAddress(libHandle, "DsReplicaGetInfoW"); 331 if (functionPtr == (IntPtr)0) 332 { 333 throw ExceptionHelper.GetExceptionFromErrorCode(Marshal.GetLastWin32Error()); 334 } 335 UnsafeNativeMethods.DsReplicaGetInfoW dsReplicaGetInfoW = (UnsafeNativeMethods.DsReplicaGetInfoW)Marshal.GetDelegateForFunctionPointer(functionPtr, typeof(UnsafeNativeMethods.DsReplicaGetInfoW)); 336 result = dsReplicaGetInfoW(dsHandle, secondaryType, partition, (IntPtr)0, ref info); 337 advanced = false; 338 needToTryAgain = false; 339 } 340 else 341 { 342 UnsafeNativeMethods.DsReplicaGetInfo2W dsReplicaGetInfo2W = (UnsafeNativeMethods.DsReplicaGetInfo2W)Marshal.GetDelegateForFunctionPointer(functionPtr, typeof(UnsafeNativeMethods.DsReplicaGetInfo2W)); 343 result = dsReplicaGetInfo2W(dsHandle, type, partition, (IntPtr)0, null, null, 0, context, ref info); 344 } 345 346 // check the result 347 if (needToTryAgain && result == DS_REPL_NOTSUPPORTED) 348 { 349 // this is the case that client is xp/win2k3, dc is win2k 350 functionPtr = UnsafeNativeMethods.GetProcAddress(libHandle, "DsReplicaGetInfoW"); 351 if (functionPtr == (IntPtr)0) 352 { 353 throw ExceptionHelper.GetExceptionFromErrorCode(Marshal.GetLastWin32Error()); 354 } 355 UnsafeNativeMethods.DsReplicaGetInfoW dsReplicaGetInfoW = (UnsafeNativeMethods.DsReplicaGetInfoW)Marshal.GetDelegateForFunctionPointer(functionPtr, typeof(UnsafeNativeMethods.DsReplicaGetInfoW)); 356 357 result = dsReplicaGetInfoW(dsHandle, secondaryType, partition, (IntPtr)0, ref info); 358 advanced = false; 359 } 360 361 if (result != 0) 362 { 363 if (partition != null) 364 { 365 // this is the case of meta data 366 if (type == (int)DS_REPL_INFO_TYPE.DS_REPL_INFO_METADATA_2_FOR_OBJ) 367 { 368 if (result == ExceptionHelper.ERROR_DS_DRA_BAD_DN || result == ExceptionHelper.ERROR_DS_NAME_UNPARSEABLE) 369 throw new ArgumentException(ExceptionHelper.GetErrorMessage(result, false), "objectPath"); 370 371 DirectoryEntry verifyEntry = DirectoryEntryManager.GetDirectoryEntry(this.context, partition); 372 try 373 { 374 verifyEntry.RefreshCache(new string[] { "name" }); 375 } 376 catch (COMException e) 377 { 378 if (e.ErrorCode == unchecked((int)0x80072020) | // dir_error on server side 379 e.ErrorCode == unchecked((int)0x80072030)) // object not exists 380 throw new ArgumentException(SR.DSNoObject, "objectPath"); 381 else if (e.ErrorCode == unchecked((int)0x80005000) | // bad path name 382 e.ErrorCode == unchecked((int)0x80072032)) // ERROR_DS_INVALID_DN_SYNTAX 383 throw new ArgumentException(SR.DSInvalidPath, "objectPath"); 384 } 385 } 386 else 387 { 388 if (!Partitions.Contains(partition)) 389 throw new ArgumentException(SR.ServerNotAReplica, "partition"); 390 } 391 } 392 393 throw ExceptionHelper.GetExceptionFromErrorCode(result, Name); 394 } 395 396 return info; 397 } 398 ConstructReplicationCursors(IntPtr dsHandle, bool advanced, IntPtr info, string partition, DirectoryServer server, LoadLibrarySafeHandle libHandle)399 internal ReplicationCursorCollection ConstructReplicationCursors(IntPtr dsHandle, bool advanced, IntPtr info, string partition, DirectoryServer server, LoadLibrarySafeHandle libHandle) 400 { 401 int context = 0; 402 int count = 0; 403 ReplicationCursorCollection collection = new ReplicationCursorCollection(server); 404 405 // construct the collection 406 if (advanced) 407 { 408 // using paging to get all the results 409 while (true) 410 { 411 try 412 { 413 if (info != (IntPtr)0) 414 { 415 DS_REPL_CURSORS_3 cursors = new DS_REPL_CURSORS_3(); 416 Marshal.PtrToStructure(info, cursors); 417 count = cursors.cNumCursors; 418 if (count > 0) 419 collection.AddHelper(partition, cursors, advanced, info); 420 421 context = cursors.dwEnumerationContext; 422 423 // we already get all the results or there is no result 424 if (context == -1 || count == 0) 425 break; 426 } 427 else 428 { 429 // should not happen, treat as no result is returned. 430 break; 431 } 432 } 433 finally 434 { 435 FreeReplicaInfo(DS_REPL_INFO_TYPE.DS_REPL_INFO_CURSORS_3_FOR_NC, info, libHandle); 436 } 437 438 // get the next batch of results 439 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, libHandle); 440 } 441 } 442 else 443 { 444 try 445 { 446 if (info != (IntPtr)0) 447 { 448 // structure of DS_REPL_CURSORS_3 and DS_REPL_CURSORS actually are the same 449 DS_REPL_CURSORS cursors = new DS_REPL_CURSORS(); 450 Marshal.PtrToStructure(info, cursors); 451 452 collection.AddHelper(partition, cursors, advanced, info); 453 } 454 } 455 finally 456 { 457 FreeReplicaInfo(DS_REPL_INFO_TYPE.DS_REPL_INFO_CURSORS_FOR_NC, info, libHandle); 458 } 459 } 460 461 return collection; 462 } 463 ConstructPendingOperations(IntPtr info, DirectoryServer server, LoadLibrarySafeHandle libHandle)464 internal ReplicationOperationInformation ConstructPendingOperations(IntPtr info, DirectoryServer server, LoadLibrarySafeHandle libHandle) 465 { 466 ReplicationOperationInformation replicationInfo = new ReplicationOperationInformation(); 467 ReplicationOperationCollection collection = new ReplicationOperationCollection(server); 468 replicationInfo.collection = collection; 469 int count = 0; 470 471 try 472 { 473 if (info != (IntPtr)0) 474 { 475 DS_REPL_PENDING_OPS operations = new DS_REPL_PENDING_OPS(); 476 Marshal.PtrToStructure(info, operations); 477 count = operations.cNumPendingOps; 478 if (count > 0) 479 { 480 collection.AddHelper(operations, info); 481 replicationInfo.startTime = DateTime.FromFileTime(operations.ftimeCurrentOpStarted); 482 replicationInfo.currentOp = collection.GetFirstOperation(); 483 } 484 } 485 } 486 finally 487 { 488 FreeReplicaInfo(DS_REPL_INFO_TYPE.DS_REPL_INFO_PENDING_OPS, info, libHandle); 489 } 490 return replicationInfo; 491 } 492 ConstructNeighbors(IntPtr info, DirectoryServer server, LoadLibrarySafeHandle libHandle)493 internal ReplicationNeighborCollection ConstructNeighbors(IntPtr info, DirectoryServer server, LoadLibrarySafeHandle libHandle) 494 { 495 ReplicationNeighborCollection collection = new ReplicationNeighborCollection(server); 496 int count = 0; 497 498 try 499 { 500 if (info != (IntPtr)0) 501 { 502 DS_REPL_NEIGHBORS neighbors = new DS_REPL_NEIGHBORS(); 503 Marshal.PtrToStructure(info, neighbors); 504 Debug.Assert(neighbors != null); 505 count = neighbors.cNumNeighbors; 506 if (count > 0) 507 collection.AddHelper(neighbors, info); 508 } 509 } 510 finally 511 { 512 FreeReplicaInfo(DS_REPL_INFO_TYPE.DS_REPL_INFO_NEIGHBORS, info, libHandle); 513 } 514 return collection; 515 } 516 ConstructFailures(IntPtr info, DirectoryServer server, LoadLibrarySafeHandle libHandle)517 internal ReplicationFailureCollection ConstructFailures(IntPtr info, DirectoryServer server, LoadLibrarySafeHandle libHandle) 518 { 519 ReplicationFailureCollection collection = new ReplicationFailureCollection(server); 520 int count = 0; 521 522 try 523 { 524 if (info != (IntPtr)0) 525 { 526 DS_REPL_KCC_DSA_FAILURES failures = new DS_REPL_KCC_DSA_FAILURES(); 527 Marshal.PtrToStructure(info, failures); 528 count = failures.cNumEntries; 529 if (count > 0) 530 collection.AddHelper(failures, info); 531 } 532 } 533 finally 534 { 535 FreeReplicaInfo(DS_REPL_INFO_TYPE.DS_REPL_INFO_KCC_DSA_CONNECT_FAILURES, info, libHandle); 536 } 537 return collection; 538 } 539 ConstructMetaData(bool advanced, IntPtr info, DirectoryServer server, LoadLibrarySafeHandle libHandle)540 internal ActiveDirectoryReplicationMetadata ConstructMetaData(bool advanced, IntPtr info, DirectoryServer server, LoadLibrarySafeHandle libHandle) 541 { 542 ActiveDirectoryReplicationMetadata collection = new ActiveDirectoryReplicationMetadata(server); 543 int count = 0; 544 545 if (advanced) 546 { 547 try 548 { 549 if (info != (IntPtr)0) 550 { 551 DS_REPL_OBJ_META_DATA_2 objMetaData = new DS_REPL_OBJ_META_DATA_2(); 552 Marshal.PtrToStructure(info, objMetaData); 553 554 count = objMetaData.cNumEntries; 555 if (count > 0) 556 { 557 collection.AddHelper(count, info, true); 558 } 559 } 560 } 561 finally 562 { 563 FreeReplicaInfo(DS_REPL_INFO_TYPE.DS_REPL_INFO_METADATA_2_FOR_OBJ, info, libHandle); 564 } 565 } 566 else 567 { 568 try 569 { 570 DS_REPL_OBJ_META_DATA objMetadata = new DS_REPL_OBJ_META_DATA(); 571 Marshal.PtrToStructure(info, objMetadata); 572 573 count = objMetadata.cNumEntries; 574 if (count > 0) 575 { 576 collection.AddHelper(count, info, false); 577 } 578 } 579 finally 580 { 581 FreeReplicaInfo(DS_REPL_INFO_TYPE.DS_REPL_INFO_METADATA_FOR_OBJ, info, libHandle); 582 } 583 } 584 585 return collection; 586 } 587 SyncAllCallbackRoutine(IntPtr data, IntPtr update)588 internal bool SyncAllCallbackRoutine(IntPtr data, IntPtr update) 589 { 590 if (SyncFromAllServersCallback == null) 591 { 592 // user does not specify callback, resume the DsReplicaSyncAll execution 593 return true; 594 } 595 else 596 { 597 // user specifies callback 598 // our callback is invoked, update should not be NULL, do assertion here 599 Debug.Assert(update != (IntPtr)0); 600 601 DS_REPSYNCALL_UPDATE syncAllUpdate = new DS_REPSYNCALL_UPDATE(); 602 Marshal.PtrToStructure(update, syncAllUpdate); 603 604 // get the event type 605 SyncFromAllServersEvent eventType = syncAllUpdate.eventType; 606 607 // get the error information 608 IntPtr temp = syncAllUpdate.pErrInfo; 609 SyncFromAllServersOperationException exception = null; 610 611 if (temp != (IntPtr)0) 612 { 613 // error information is available 614 exception = ExceptionHelper.CreateSyncAllException(temp, true); 615 if (exception == null) 616 { 617 // this is the special case that we ingore the failure when SyncAllOptions.CheckServerAlivenessOnly is specified 618 return true; 619 } 620 } 621 622 string targetName = null; 623 string sourceName = null; 624 625 temp = syncAllUpdate.pSync; 626 if (temp != (IntPtr)0) 627 { 628 DS_REPSYNCALL_SYNC sync = new DS_REPSYNCALL_SYNC(); 629 Marshal.PtrToStructure(temp, sync); 630 631 targetName = Marshal.PtrToStringUni(sync.pszDstId); 632 sourceName = Marshal.PtrToStringUni(sync.pszSrcId); 633 } 634 635 // invoke the client callback 636 SyncUpdateCallback clientCallback = SyncFromAllServersCallback; 637 638 return clientCallback(eventType, targetName, sourceName, exception); 639 } 640 } 641 SyncReplicaAllHelper(IntPtr handle, SyncReplicaFromAllServersCallback syncAllFunctionPointer, string partition, SyncFromAllServersOptions option, SyncUpdateCallback callback, LoadLibrarySafeHandle libHandle)642 internal void SyncReplicaAllHelper(IntPtr handle, SyncReplicaFromAllServersCallback syncAllFunctionPointer, string partition, SyncFromAllServersOptions option, SyncUpdateCallback callback, LoadLibrarySafeHandle libHandle) 643 { 644 IntPtr errorInfo = (IntPtr)0; 645 646 if (!Partitions.Contains(partition)) 647 throw new ArgumentException(SR.ServerNotAReplica, "partition"); 648 649 // we want to return the dn instead of DNS guid 650 // call DsReplicaSyncAllW 651 IntPtr functionPtr = UnsafeNativeMethods.GetProcAddress(libHandle, "DsReplicaSyncAllW"); 652 if (functionPtr == (IntPtr)0) 653 { 654 throw ExceptionHelper.GetExceptionFromErrorCode(Marshal.GetLastWin32Error()); 655 } 656 UnsafeNativeMethods.DsReplicaSyncAllW dsReplicaSyncAllW = (UnsafeNativeMethods.DsReplicaSyncAllW)Marshal.GetDelegateForFunctionPointer(functionPtr, typeof(UnsafeNativeMethods.DsReplicaSyncAllW)); 657 658 int result = dsReplicaSyncAllW(handle, partition, (int)option | DS_REPSYNCALL_ID_SERVERS_BY_DN, syncAllFunctionPointer, (IntPtr)0, ref errorInfo); 659 660 try 661 { 662 // error happens during the synchronization 663 if (errorInfo != (IntPtr)0) 664 { 665 SyncFromAllServersOperationException e = ExceptionHelper.CreateSyncAllException(errorInfo, false); 666 if (e == null) 667 return; 668 else 669 throw e; 670 } 671 else 672 { 673 // API does not return error infor occurred during synchronization, but result is not success. 674 if (result != 0) 675 throw new SyncFromAllServersOperationException(ExceptionHelper.GetErrorMessage(result, false)); 676 } 677 } 678 finally 679 { 680 // release the memory 681 if (errorInfo != (IntPtr)0) 682 UnsafeNativeMethods.LocalFree(errorInfo); 683 } 684 } 685 FreeReplicaInfo(DS_REPL_INFO_TYPE type, IntPtr value, LoadLibrarySafeHandle libHandle)686 private void FreeReplicaInfo(DS_REPL_INFO_TYPE type, IntPtr value, LoadLibrarySafeHandle libHandle) 687 { 688 if (value != (IntPtr)0) 689 { 690 // call DsReplicaFreeInfo 691 IntPtr functionPtr = UnsafeNativeMethods.GetProcAddress(libHandle, "DsReplicaFreeInfo"); 692 if (functionPtr == (IntPtr)0) 693 { 694 throw ExceptionHelper.GetExceptionFromErrorCode(Marshal.GetLastWin32Error()); 695 } 696 UnsafeNativeMethods.DsReplicaFreeInfo dsReplicaFreeInfo = (UnsafeNativeMethods.DsReplicaFreeInfo)Marshal.GetDelegateForFunctionPointer(functionPtr, typeof(UnsafeNativeMethods.DsReplicaFreeInfo)); 697 698 dsReplicaFreeInfo((int)type, value); 699 } 700 } 701 SyncReplicaHelper(IntPtr dsHandle, bool isADAM, string partition, string sourceServer, int option, LoadLibrarySafeHandle libHandle)702 internal void SyncReplicaHelper(IntPtr dsHandle, bool isADAM, string partition, string sourceServer, int option, LoadLibrarySafeHandle libHandle) 703 { 704 int structSize = Marshal.SizeOf(typeof(Guid)); 705 IntPtr unmanagedGuid = (IntPtr)0; 706 Guid guid = Guid.Empty; 707 AdamInstance adamServer = null; 708 DomainController dcServer = null; 709 710 unmanagedGuid = Marshal.AllocHGlobal(structSize); 711 try 712 { 713 if (sourceServer != null) 714 { 715 DirectoryContext newContext = Utils.GetNewDirectoryContext(sourceServer, DirectoryContextType.DirectoryServer, context); 716 if (isADAM) 717 { 718 adamServer = AdamInstance.GetAdamInstance(newContext); 719 guid = adamServer.NtdsaObjectGuid; 720 } 721 else 722 { 723 dcServer = DomainController.GetDomainController(newContext); 724 guid = dcServer.NtdsaObjectGuid; 725 } 726 727 Marshal.StructureToPtr(guid, unmanagedGuid, false); 728 } 729 730 // call DsReplicaSyncW 731 IntPtr functionPtr = UnsafeNativeMethods.GetProcAddress(libHandle, "DsReplicaSyncW"); 732 if (functionPtr == (IntPtr)0) 733 { 734 throw ExceptionHelper.GetExceptionFromErrorCode(Marshal.GetLastWin32Error()); 735 } 736 UnsafeNativeMethods.DsReplicaSyncW dsReplicaSyncW = (UnsafeNativeMethods.DsReplicaSyncW)Marshal.GetDelegateForFunctionPointer(functionPtr, typeof(UnsafeNativeMethods.DsReplicaSyncW)); 737 738 int result = dsReplicaSyncW(dsHandle, partition, unmanagedGuid, (int)option); 739 740 // check the result 741 if (result != 0) 742 { 743 if (!Partitions.Contains(partition)) 744 throw new ArgumentException(SR.ServerNotAReplica, "partition"); 745 746 string serverDownName = null; 747 // this is the error returned when the server that we want to sync from is down 748 if (result == ExceptionHelper.RPC_S_SERVER_UNAVAILABLE) 749 serverDownName = sourceServer; 750 // this is the error returned when the server that we want to get synced is down 751 else if (result == ExceptionHelper.RPC_S_CALL_FAILED) 752 serverDownName = Name; 753 754 throw ExceptionHelper.GetExceptionFromErrorCode(result, serverDownName); 755 } 756 } 757 finally 758 { 759 if (unmanagedGuid != (IntPtr)0) 760 Marshal.FreeHGlobal(unmanagedGuid); 761 762 if (adamServer != null) 763 adamServer.Dispose(); 764 765 if (dcServer != null) 766 dcServer.Dispose(); 767 } 768 } 769 GetInboundConnectionsHelper()770 internal ReplicationConnectionCollection GetInboundConnectionsHelper() 771 { 772 if (_inbound == null) 773 { 774 // construct the replicationconnection collection 775 _inbound = new ReplicationConnectionCollection(); 776 DirectoryContext newContext = Utils.GetNewDirectoryContext(Name, DirectoryContextType.DirectoryServer, context); 777 778 // this is the first time that user tries to retrieve this property, so get it from the directory 779 string serverName = (this is DomainController) ? ((DomainController)this).ServerObjectName : ((AdamInstance)this).ServerObjectName; 780 string srchDN = "CN=NTDS Settings," + serverName; 781 DirectoryEntry de = DirectoryEntryManager.GetDirectoryEntry(Utils.GetNewDirectoryContext(Name, DirectoryContextType.DirectoryServer, context), srchDN); 782 783 ADSearcher adSearcher = new ADSearcher(de, 784 "(&(objectClass=nTDSConnection)(objectCategory=nTDSConnection))", 785 new string[] { "cn" }, 786 SearchScope.OneLevel); 787 SearchResultCollection srchResults = null; 788 789 try 790 { 791 srchResults = adSearcher.FindAll(); 792 foreach (SearchResult r in srchResults) 793 { 794 ReplicationConnection con = new ReplicationConnection(newContext, r.GetDirectoryEntry(), (string)PropertyManager.GetSearchResultPropertyValue(r, PropertyManager.Cn)); 795 _inbound.Add(con); 796 } 797 } 798 catch (COMException e) 799 { 800 throw ExceptionHelper.GetExceptionFromCOMException(newContext, e); 801 } 802 finally 803 { 804 if (srchResults != null) 805 srchResults.Dispose(); 806 807 de.Dispose(); 808 } 809 } 810 811 return _inbound; 812 } 813 GetOutboundConnectionsHelper()814 internal ReplicationConnectionCollection GetOutboundConnectionsHelper() 815 { 816 // this is the first time that user tries to retrieve this property, so get it from the directory 817 if (_outbound == null) 818 { 819 // search base is the site container 820 string siteName = (this is DomainController) ? ((DomainController)this).SiteObjectName : ((AdamInstance)this).SiteObjectName; 821 DirectoryEntry de = DirectoryEntryManager.GetDirectoryEntry(Utils.GetNewDirectoryContext(Name, DirectoryContextType.DirectoryServer, context), siteName); 822 823 string serverName = (this is DomainController) ? ((DomainController)this).ServerObjectName : ((AdamInstance)this).ServerObjectName; 824 ADSearcher adSearcher = new ADSearcher(de, 825 "(&(objectClass=nTDSConnection)(objectCategory=nTDSConnection)(fromServer=CN=NTDS Settings," + serverName + "))", 826 new string[] { "objectClass", "cn" }, 827 SearchScope.Subtree); 828 829 SearchResultCollection results = null; 830 DirectoryContext newContext = Utils.GetNewDirectoryContext(Name, DirectoryContextType.DirectoryServer, context); 831 832 try 833 { 834 results = adSearcher.FindAll(); 835 _outbound = new ReplicationConnectionCollection(); 836 837 foreach (SearchResult result in results) 838 { 839 ReplicationConnection con = new ReplicationConnection(newContext, result.GetDirectoryEntry(), (string)result.Properties["cn"][0]); 840 _outbound.Add(con); 841 } 842 } 843 catch (COMException e) 844 { 845 throw ExceptionHelper.GetExceptionFromCOMException(newContext, e); 846 } 847 finally 848 { 849 if (results != null) 850 results.Dispose(); 851 852 de.Dispose(); 853 } 854 } 855 856 return _outbound; 857 } 858 859 #endregion private methods 860 } 861 } 862