Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

593 lines
18 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 2000, Microsoft Corporation
  4. //
  5. // File: DfsADBlobRootFolder.cxx
  6. //
  7. // Contents: the Root DFS Folder class for ADBlob Store
  8. //
  9. // Classes: DfsADBlobRootFolder
  10. //
  11. // History: Dec. 8 2000, Author: udayh
  12. // April 14 2001 Rohanp - Modified to use ADSI code
  13. //
  14. //-----------------------------------------------------------------------------
  15. #include "DfsADBlobRootFolder.hxx"
  16. #include "DfsReplica.hxx"
  17. #include "lmdfs.h"
  18. #include "dfserror.hxx"
  19. #include "dfsmisc.h"
  20. #include "dfsadsiapi.hxx"
  21. #include "domaincontrollersupport.hxx"
  22. #include "DfsSynchronizeRoots.hxx"
  23. #if !defined(DFS_STORAGE_STATE_MASTER)
  24. #define DFS_STORAGE_STATE_MASTER 0x0010
  25. #endif
  26. #if !defined(DFS_STORAGE_STATE_STANDBY)
  27. #define DFS_STORAGE_STATE_STANDBY 0x0020
  28. #endif
  29. //
  30. // logging specific includes
  31. //
  32. #include "DfsADBlobRootFolder.tmh"
  33. //+----------------------------------------------------------------------------
  34. //
  35. // Class: DfsADBlobRootFolder
  36. //
  37. // Synopsis: This class implements The Dfs ADBlob root folder.
  38. //
  39. //-----------------------------------------------------------------------------
  40. //+-------------------------------------------------------------------------
  41. //
  42. // Function: DfsADBlobRootFolder - constructor
  43. //
  44. // Arguments: NameContext - the dfs name context
  45. // pLogicalShare - the logical share
  46. // pParentStore - the parent store for this root.
  47. // pStatus - the return status
  48. //
  49. // Returns: NONE
  50. //
  51. // Description: This routine initializes a ADBlobRootFolder instance
  52. //
  53. //--------------------------------------------------------------------------
  54. DfsADBlobRootFolder::DfsADBlobRootFolder(
  55. LPWSTR NameContext,
  56. LPWSTR pRootRegistryNameString,
  57. PUNICODE_STRING pLogicalShare,
  58. PUNICODE_STRING pPhysicalShare,
  59. DfsADBlobStore *pParentStore,
  60. DFSSTATUS *pStatus ) : DfsRootFolder ( NameContext,
  61. pRootRegistryNameString,
  62. pLogicalShare,
  63. pPhysicalShare,
  64. DFS_OBJECT_TYPE_ADBLOB_ROOT_FOLDER,
  65. pStatus )
  66. {
  67. DFSSTATUS Status = *pStatus;
  68. _pBlobCache = NULL;
  69. _pStore = pParentStore;
  70. if (_pStore != NULL)
  71. {
  72. _pStore->AcquireReference();
  73. }
  74. _RootFlavor = DFS_VOLUME_FLAVOR_AD_BLOB;
  75. //
  76. // If the namecontext that we are passed is an emptry string,
  77. // then we are dealing with the referral server running on the root
  78. // itself. We are required to ignore the name context for such
  79. // roots during lookups, so that aliasing works. (Aliasing is where
  80. // someone may access the root with an aliased machine name or ip
  81. // address)
  82. //
  83. if (Status == ERROR_SUCCESS)
  84. {
  85. if (IsEmptyString(NameContext) == TRUE)
  86. {
  87. SetIgnoreNameContext();
  88. _LocalCreate = TRUE;
  89. //
  90. // Now we update our visible context, which is the dfs name context
  91. // seen by people when they do api calls.
  92. // For the ad blob root folder, this will be the domain name of this
  93. // machine.
  94. //
  95. Status = DfsGetDomainName( &_DfsVisibleContext );
  96. }
  97. else
  98. {
  99. Status = DfsCreateUnicodeStringFromString(&_DfsVisibleContext, NameContext);
  100. }
  101. }
  102. if (Status == ERROR_SUCCESS)
  103. {
  104. _pBlobCache = new DfsADBlobCache(&Status, GetLogicalShare(), this);
  105. if ( _pBlobCache == NULL )
  106. {
  107. Status = ERROR_NOT_ENOUGH_MEMORY;
  108. }
  109. //
  110. // If the constructor returns an error, the caller will release the reference
  111. // on this BlobCache which in turn will desctruct it.
  112. //
  113. }
  114. *pStatus = Status;
  115. DFS_TRACE_LOW(REFERRAL_SERVER, "Created new root folder,%p, cache %p, name %wZ\n",
  116. this, _pBlobCache, GetLogicalShare());
  117. }
  118. //+-------------------------------------------------------------------------
  119. //
  120. // Function: Synchronize
  121. //
  122. // Arguments: None
  123. //
  124. // Returns: Status: Success or Error status code
  125. //
  126. // Description: This routine synchronizes the children folders
  127. // of this root.
  128. //
  129. //--------------------------------------------------------------------------
  130. DFSSTATUS
  131. DfsADBlobRootFolder::Synchronize(BOOLEAN fForceSync, BOOLEAN CalledByApi )
  132. {
  133. DFSSTATUS Status = ERROR_SUCCESS;
  134. //
  135. // Read from the metadata store, and unravel the blob.
  136. // Update the ADBlobCache with the information of each individual
  137. // link, deleting old inof, adding new info, and/or modifying
  138. // existing information.
  139. //
  140. //
  141. // if we are in a standby mode, we dont synchronize, till we obtain
  142. // ownership again.
  143. //
  144. DFS_TRACE_LOW(REFERRAL_SERVER, "Synchronize started on root %p (%wZ)\n", this, GetLogicalShare());
  145. Status = AcquireRootLock();
  146. if (Status != ERROR_SUCCESS)
  147. {
  148. return Status;
  149. }
  150. if (CheckRootFolderSkipSynchronize() == TRUE)
  151. {
  152. ReleaseRootLock();
  153. return ERROR_SUCCESS;
  154. }
  155. //
  156. // now acquire the root share directory. If this
  157. // fails, we continue our operation: we can continue
  158. // with synchonize and not create directories.
  159. // dfsdev:we need to post a eventlog or something when
  160. // we run into this.
  161. //
  162. do
  163. {
  164. DFSSTATUS RootStatus = AcquireRootShareDirectory();
  165. if(CalledByApi && (RootStatus != ERROR_SUCCESS))
  166. {
  167. DFS_TRACE_ERROR_LOW(RootStatus, REFERRAL_SERVER, "Recognize Dfs: Root folder for %p, validate status %x\n",
  168. this, RootStatus );
  169. Status = RootStatus;
  170. break;
  171. }
  172. if (IsRootScalabilityMode() == TRUE)
  173. {
  174. //
  175. // Dont have to get blob from PDC
  176. //
  177. Status = UpdateRootFromBlob(fForceSync, FALSE);
  178. DFS_TRACE_LOW(REFERRAL_SERVER, "Loose Sync, Update root from blob Status %x\n", Status);
  179. }
  180. else
  181. {
  182. //
  183. // have to to get blob from PDC
  184. //
  185. Status = UpdateRootFromBlob(fForceSync, TRUE);
  186. DFS_TRACE_LOW(REFERRAL_SERVER, "Tight Sync, Update root from blob Status %x\n", Status);
  187. }
  188. if(CalledByApi && (Status != ERROR_SUCCESS))
  189. {
  190. DFS_TRACE_ERROR_LOW(Status, REFERRAL_SERVER, "Recognize Dfs: Synchronize Root folder for %p, validate status %x\n",
  191. this, Status );
  192. (void) ReleaseRootShareDirectory();
  193. }
  194. } while (0);
  195. ReleaseRootLock();
  196. DFS_TRACE_LOW(REFERRAL_SERVER, "Synchronize done on root %p, Status %x\n", this, Status);
  197. return Status;
  198. }
  199. DFSSTATUS
  200. DfsADBlobRootFolder::UpdateRootFromBlob(
  201. BOOLEAN fForceSync,
  202. BOOLEAN FromPDC)
  203. {
  204. DFSSTATUS Status;
  205. //
  206. // Read in the blob from the AD, enumerate it,
  207. // and put the data in the cache.
  208. //
  209. Status = GetMetadataBlobCache()->CacheRefresh( fForceSync,
  210. FromPDC );
  211. if (Status == ERROR_SUCCESS)
  212. {
  213. Status = EnumerateBlobCacheAndCreateFolders( );
  214. if (Status == ERROR_SUCCESS)
  215. {
  216. //
  217. // Mark it so we know the root folder has finished
  218. // syncing.
  219. //
  220. SetRootFolderSynchronized();
  221. }
  222. else
  223. {
  224. ClearRootFolderSynchronized();
  225. }
  226. }
  227. return Status;
  228. }
  229. DFSSTATUS
  230. DfsADBlobRootFolder::EnumerateBlobCacheAndCreateFolders( )
  231. {
  232. DFSSTATUS UpdateStatus;
  233. DFSSTATUS Status = STATUS_SUCCESS;
  234. DfsADBlobCache * pBlobCache = NULL;
  235. PDFSBLOB_DATA pBlobData = NULL;
  236. DFSBOB_ITER Iter;
  237. pBlobCache = GetMetadataBlobCache();
  238. pBlobData = pBlobCache->FindFirstBlob(&Iter);
  239. while (pBlobData && (!DfsIsShuttingDown()))
  240. {
  241. if (pBlobCache->IsStaleBlob(pBlobData))
  242. {
  243. DFSSTATUS RemoveStatus;
  244. RemoveStatus = RemoveLinkFolder( pBlobData->BlobName.Buffer );
  245. DFS_TRACE_ERROR_LOW(RemoveStatus, REFERRAL_SERVER, "Remove stale folder %ws, status %x\n",
  246. pBlobData->BlobName.Buffer,
  247. RemoveStatus );
  248. if (RemoveStatus == ERROR_SUCCESS)
  249. {
  250. RemoveStatus = pBlobCache->RemoveNamedBlob( &pBlobData->BlobName );
  251. }
  252. DFS_TRACE_ERROR_LOW(RemoveStatus, REFERRAL_SERVER, "Remove stale folder %ws, status %x\n",
  253. pBlobData->BlobName.Buffer,
  254. RemoveStatus );
  255. }
  256. pBlobData = pBlobCache->FindNextBlob(&Iter);
  257. }
  258. pBlobCache->FindCloseBlob(&Iter);
  259. pBlobData = pBlobCache->FindFirstBlob(&Iter);
  260. while (pBlobData && (!DfsIsShuttingDown()))
  261. {
  262. if (pBlobCache->IsStaleBlob(pBlobData) == FALSE)
  263. {
  264. UpdateStatus = UpdateLinkInformation((DFS_METADATA_HANDLE) pBlobCache,
  265. pBlobData->BlobName.Buffer);
  266. DFS_TRACE_ERROR_LOW(UpdateStatus, REFERRAL_SERVER,
  267. "Root %p (%wZ) Ad Blob enumerate, update link returned %x for %wZ\n",
  268. this, GetLogicalShare(), UpdateStatus, &pBlobData->BlobName);
  269. if (UpdateStatus != ERROR_SUCCESS)
  270. {
  271. Status = UpdateStatus;
  272. }
  273. }
  274. pBlobData = pBlobCache->FindNextBlob(&Iter);
  275. }
  276. pBlobCache->FindCloseBlob(&Iter);
  277. DFS_TRACE_ERROR_LOW(Status, REFERRAL_SERVER,
  278. "Root %p (%wZ) Done with Enumerate blob and create folders, Status %x\n",
  279. this, GetLogicalShare(), Status);
  280. return Status;
  281. }
  282. //+-------------------------------------------------------------------------
  283. //
  284. // Function: RenameLinks
  285. //
  286. // Arguments:
  287. // OldDomainName
  288. // NewDomainName
  289. //
  290. // Returns: SUCCESS or error
  291. //
  292. // Description: Renames all links referencing the old domain name to the new.
  293. //--------------------------------------------------------------------------
  294. DFSSTATUS
  295. DfsADBlobRootFolder::RenameLinks(
  296. IN LPWSTR OldDomainName,
  297. IN LPWSTR NewDomainName)
  298. {
  299. DFSSTATUS Status = ERROR_SUCCESS;
  300. DfsADBlobCache * pBlobCache = NULL;
  301. PDFSBLOB_DATA pBlobData = NULL;
  302. DFS_METADATA_HANDLE RootHandle = NULL;
  303. PUNICODE_STRING pLinkMetadataName = NULL;
  304. UNICODE_STRING OldUnicodeName, NewUnicodeName;
  305. DFSBOB_ITER Iter;
  306. Status = AcquireRootLock();
  307. if (Status != ERROR_SUCCESS)
  308. {
  309. return Status;
  310. }
  311. Status = DfsRtlInitUnicodeStringEx( &OldUnicodeName, OldDomainName );
  312. if (Status != ERROR_SUCCESS)
  313. {
  314. goto Exit;
  315. }
  316. Status = DfsRtlInitUnicodeStringEx( &NewUnicodeName, NewDomainName );
  317. if (Status != ERROR_SUCCESS)
  318. {
  319. goto Exit;
  320. }
  321. pBlobCache = GetMetadataBlobCache();
  322. RootHandle = CreateMetadataHandle(pBlobCache);
  323. //
  324. // Iterate over all the blobs and rename its links
  325. // if applicable. The root blob itself is in here distinguished
  326. // by an empty LinkMetadataName (ie. \DomainRoot\"").
  327. //
  328. for (pBlobData = pBlobCache->FindFirstBlob(&Iter);
  329. pBlobData != NULL;
  330. pBlobData = pBlobCache->FindNextBlob(&Iter))
  331. {
  332. if (pBlobCache->IsStaleBlob(pBlobData))
  333. continue;
  334. pLinkMetadataName = &pBlobData->BlobName;
  335. //
  336. // Go through all the replicas in this blob and rename
  337. // them if need be. This will set the modified metadata back in the cache.
  338. // We can't continue if we've hit an error at any point. This is an
  339. // atomic rename.
  340. //
  341. Status = GetMetadataStore()->RenameLinks( RootHandle,
  342. pLinkMetadataName,
  343. &OldUnicodeName,
  344. &NewUnicodeName );
  345. if (Status != ERROR_SUCCESS)
  346. break;
  347. }
  348. pBlobCache->FindCloseBlob(&Iter);
  349. //
  350. // Now rename the remoteServerName attribute in the AD as well.
  351. //
  352. if (Status == ERROR_SUCCESS)
  353. {
  354. DFSSTATUS DeleteStatus = ERROR_SUCCESS;
  355. BOOLEAN NeedToDelete = FALSE;
  356. //
  357. // When DfsDnsConfig flag is on, the server name with FQDN
  358. // gets put on the remoteServerName attribute. See if the old
  359. // name is there. This will do a GetEx on the AD object to find out.
  360. //
  361. DeleteStatus = DfsIsRemoteServerNameEqual( GetLogicalShare()->Buffer,
  362. &OldUnicodeName,
  363. &NeedToDelete );
  364. // The return status isn't propagated outside. There's no need for it.
  365. if (DeleteStatus == ERROR_SUCCESS && NeedToDelete)
  366. {
  367. UNICODE_STRING Context;
  368. DeleteStatus = GetVisibleContext(&Context);
  369. //
  370. // Context here will give us the DC to contact
  371. // for this root. The DomainName referred to here isn't necessarily a domain name.
  372. // For this it's actually the root target name. The only reason users want to
  373. // change the remoteServerName attribute when doing domain renames is if
  374. // the DfsDnsConfig flag is set and that attribute has the fullyqualified servername in it.
  375. //
  376. if (DeleteStatus == ERROR_SUCCESS)
  377. {
  378. DeleteStatus = DfsUpdateRootRemoteServerName( GetLogicalShare()->Buffer,
  379. Context.Buffer,
  380. OldDomainName,
  381. GetRootPhysicalShareName()->Buffer,
  382. FALSE );
  383. //
  384. // Now, add the new one.
  385. //
  386. if (DeleteStatus == ERROR_SUCCESS)
  387. {
  388. Status = DfsUpdateRootRemoteServerName( GetLogicalShare()->Buffer,
  389. Context.Buffer,
  390. NewDomainName,
  391. GetRootPhysicalShareName()->Buffer,
  392. TRUE );
  393. }
  394. ReleaseVisibleContext(&Context);
  395. }
  396. }
  397. }
  398. //
  399. // Flush the cache to make our changes permanent. If there were errors
  400. // purge our changes and refresh our cache.
  401. //
  402. if (Status == ERROR_SUCCESS)
  403. {
  404. Flush();
  405. } else
  406. {
  407. ReSynchronize( TRUE );
  408. }
  409. if(RootHandle != NULL)
  410. {
  411. ReleaseMetadataHandle( RootHandle );
  412. }
  413. Exit:
  414. ReleaseRootLock();
  415. return Status;
  416. }
  417. VOID
  418. DfsADBlobRootFolder::SynchronizeRoots( )
  419. {
  420. DfsFolderReferralData *pReferralData = NULL;
  421. DFS_INFO_101 DfsState;
  422. DFSSTATUS Status, SyncStatus;
  423. DfsReplica *pReplica = NULL;
  424. ULONG Target = 0;
  425. UNICODE_STRING DfsName;
  426. PUNICODE_STRING pRootShare;
  427. ULONG SyncCount = 0, ReplicaCount = 0;
  428. BOOLEAN CacheHit = FALSE;
  429. if (IsRootScalabilityMode() == TRUE)
  430. {
  431. DFS_TRACE_LOW(REFERRAL_SERVER, "Loose Sync updates not sent to target servers\n");
  432. return;
  433. }
  434. DfsState.State = DFS_STORAGE_STATE_MASTER;
  435. pRootShare = GetLogicalShare();
  436. Status = GetReferralData( &pReferralData,
  437. &CacheHit);
  438. if (Status == ERROR_SUCCESS)
  439. {
  440. ReplicaCount = pReferralData->ReplicaCount;
  441. for (Target = 0; Target < pReferralData->ReplicaCount; Target++)
  442. {
  443. PUNICODE_STRING pTargetServer, pTargetFolder;
  444. pReplica = &pReferralData->pReplicas[ Target ];
  445. pTargetServer = pReplica->GetTargetServer();
  446. pTargetFolder = pRootShare;
  447. if (DfsIsTargetCurrentMachine(pTargetServer))
  448. {
  449. continue;
  450. }
  451. Status = DfsCreateUnicodePathString( &DfsName,
  452. 2,
  453. pTargetServer->Buffer,
  454. pTargetFolder->Buffer );
  455. if (Status == ERROR_SUCCESS)
  456. {
  457. SyncStatus = AddRootToSyncrhonize( &DfsName );
  458. if (SyncStatus == ERROR_SUCCESS)
  459. {
  460. SyncCount++;
  461. }
  462. DfsFreeUnicodeString( &DfsName );
  463. }
  464. if (DfsIsShuttingDown())
  465. {
  466. break;
  467. }
  468. }
  469. pReferralData->ReleaseReference();
  470. }
  471. DFS_TRACE_LOW( REFERRAL_SERVER, "Synchronize roots %wZ done: %x roots, %x succeeded\n",
  472. pRootShare, ReplicaCount, SyncCount);
  473. return NOTHING;
  474. }