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.

1575 lines
50 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 2000, Microsoft Corporation
  4. //
  5. // File: DfsReferral.cxx
  6. //
  7. // Contents: This file contains the functionality to generate a referral
  8. //
  9. //
  10. // History: Jan 16 2001, Authors: RohanP/UdayH
  11. //
  12. //-----------------------------------------------------------------------------
  13. #include "DfsReferral.hxx"
  14. #include "Align.h"
  15. #include "dfstrusteddomain.hxx"
  16. #include "dfsadsiapi.hxx"
  17. #include "DfsDomainInformation.hxx"
  18. #include "DomainControllerSupport.hxx"
  19. #include "dfscompat.hxx"
  20. #include "dfsreferral.tmh" // logging
  21. LONG ShuffleFudgeFactor = 0;
  22. extern "C" {
  23. DWORD
  24. I_NetDfsIsThisADomainName(
  25. IN LPWSTR wszName);
  26. }
  27. //+-------------------------------------------------------------------------
  28. //
  29. // Function: DfsGetRootFolder
  30. //
  31. // Arguments: pName - The logical name
  32. // pRemainingName - the name beyond the root
  33. // ppRoot - the Dfs root found.
  34. //
  35. // Returns: ERROR_SUCCESS
  36. // Error code otherwise
  37. //
  38. //
  39. // Description: This routine runs through all the stores and looks up
  40. // a root with the matching name context and share name.
  41. // If multiple stores have the same share, the highest
  42. // priority store wins (the store registered first is the
  43. // highest priority store)
  44. // A referenced root is returned, and the caller is
  45. // responsible for releasing the reference.
  46. //
  47. //--------------------------------------------------------------------------
  48. DFSSTATUS
  49. DfsGetRootFolder(
  50. IN PUNICODE_STRING pName,
  51. OUT PUNICODE_STRING pRemainingName,
  52. OUT DfsRootFolder **ppRoot )
  53. {
  54. DFSSTATUS Status;
  55. UNICODE_STRING DfsNameContext, LogicalShare;
  56. // First we breakup the name into the name component, the logica
  57. // share and the rest of the name
  58. Status = DfsGetPathComponents(pName,
  59. &DfsNameContext,
  60. &LogicalShare,
  61. pRemainingName );
  62. // If either the name component or the logical share is empty, error.
  63. //
  64. if (Status == ERROR_SUCCESS) {
  65. if ((DfsNameContext.Length == 0) || (LogicalShare.Length == 0)) {
  66. Status = ERROR_INVALID_PARAMETER;
  67. }
  68. }
  69. if (Status == ERROR_SUCCESS)
  70. {
  71. Status = DfsGetRootFolder( &DfsNameContext,
  72. &LogicalShare,
  73. pRemainingName,
  74. ppRoot );
  75. }
  76. return Status;
  77. }
  78. DFSSTATUS
  79. DfsGetRootFolder(
  80. IN PUNICODE_STRING pNameContext,
  81. IN PUNICODE_STRING pLogicalShare,
  82. IN PUNICODE_STRING pRemains,
  83. OUT DfsRootFolder **ppRoot )
  84. {
  85. DFSSTATUS Status;
  86. DfsStore *pStore;
  87. UNREFERENCED_PARAMETER(pRemains);
  88. // Assume we are not going to find a root.
  89. //
  90. Status = ERROR_NOT_FOUND;
  91. //
  92. // For each store registered, see if we find a matching root. The
  93. // first matching root wins.
  94. //
  95. for (pStore = DfsServerGlobalData.pRegisteredStores;
  96. pStore != NULL;
  97. pStore = pStore->pNextRegisteredStore) {
  98. Status = pStore->LookupRoot( pNameContext,
  99. pLogicalShare,
  100. ppRoot );
  101. if (Status == ERROR_SUCCESS) {
  102. break;
  103. }
  104. }
  105. return Status;
  106. }
  107. //+-------------------------------------------------------------------------
  108. //
  109. // Function: DfsGetRootFolder
  110. //
  111. // Arguments: pName - The logical name
  112. // pRemainingName - the name beyond the root
  113. // ppRoot - the Dfs root found.
  114. //
  115. // Returns: ERROR_SUCCESS
  116. // Error code otherwise
  117. //
  118. //
  119. // Description: This routine runs through all the stores and looks up
  120. // a root with the matching name context and share name.
  121. // If multiple stores have the same share, the highest
  122. // priority store wins (the store registered first is the
  123. // highest priority store)
  124. // A referenced root is returned, and the caller is
  125. // responsible for releasing the reference.
  126. //
  127. //--------------------------------------------------------------------------
  128. DFSSTATUS
  129. DfsGetOnlyRootFolder(
  130. OUT DfsRootFolder **ppRoot )
  131. {
  132. DfsStore *pStore;
  133. DFSSTATUS Status;
  134. DfsStore *pFoundStore = NULL;
  135. ULONG RootCount;
  136. // Assume we are not going to find a root.
  137. //
  138. Status = ERROR_NOT_FOUND;
  139. //
  140. // For each store registered, see if we find a matching root. The
  141. // first matching root wins.
  142. //
  143. for (pStore = DfsServerGlobalData.pRegisteredStores;
  144. pStore != NULL;
  145. pStore = pStore->pNextRegisteredStore) {
  146. Status = pStore->GetRootCount(&RootCount);
  147. if (Status == ERROR_SUCCESS)
  148. {
  149. if ((RootCount > 1) ||
  150. (RootCount && pFoundStore))
  151. {
  152. Status = ERROR_DEVICE_NOT_AVAILABLE;
  153. break;
  154. }
  155. if (RootCount == 1)
  156. {
  157. pFoundStore = pStore;
  158. }
  159. }
  160. else
  161. {
  162. break;
  163. }
  164. }
  165. if (Status == ERROR_SUCCESS)
  166. {
  167. if (pFoundStore == NULL)
  168. {
  169. Status = ERROR_NOT_FOUND;
  170. }
  171. }
  172. if (Status == ERROR_SUCCESS)
  173. {
  174. Status = pFoundStore->FindFirstRoot( ppRoot );
  175. }
  176. return Status;
  177. }
  178. //+-------------------------------------------------------------------------
  179. //
  180. // Function: DfsLookupFolder
  181. //
  182. // Arguments: pName - name to lookup
  183. // pRemainingName - the part of the name that was unmatched
  184. // ppFolder - the folder for the matching part of the name.
  185. //
  186. // Returns: ERROR_SUCCESS
  187. // ERROR code otherwise
  188. //
  189. // Description: This routine finds the folder for the maximal path
  190. // that can be matched, and return the referenced folder
  191. // along with the remaining part of the name that had
  192. // no match.
  193. //
  194. //--------------------------------------------------------------------------
  195. DFSSTATUS
  196. DfsLookupFolder(
  197. PUNICODE_STRING pName,
  198. PUNICODE_STRING pRemainingName,
  199. DfsFolder **ppFolder )
  200. {
  201. DFSSTATUS Status = ERROR_SUCCESS;
  202. NTSTATUS NtStatus = STATUS_SUCCESS;
  203. DfsRootFolder *pRoot = NULL;
  204. DfsFolder *pFolder = NULL;
  205. UNICODE_STRING LinkName, Remaining;
  206. UNICODE_STRING LongName;
  207. UNICODE_STRING NotUsed;
  208. DFS_TRACE_LOW( REFERRAL, "DfsLookupFolder Name %wZ\n", pName);
  209. LongName.Length = LongName.MaximumLength = 0;
  210. LongName.Buffer = NULL;
  211. //
  212. // Get a root folder
  213. //
  214. Status = DfsGetRootFolder( pName,
  215. &LinkName,
  216. &pRoot );
  217. DFS_TRACE_ERROR_LOW( Status, REFERRAL, "get referral data, lookup folder %p, Status %x\n",
  218. pRoot, Status);
  219. if (Status == ERROR_SUCCESS)
  220. {
  221. //
  222. // we now check if the root folder is available for referral
  223. // requests. If not, return error.
  224. //
  225. if (pRoot->IsRootFolderAvailableForReferral() == FALSE)
  226. {
  227. Status = ERROR_DEVICE_NOT_AVAILABLE;
  228. pRoot->ReleaseReference();
  229. }
  230. }
  231. //
  232. // If we got a root folder, see if there is a link that matches
  233. // the rest of the name beyond the root.
  234. //
  235. if (Status == ERROR_SUCCESS) {
  236. if (LinkName.Length != 0) {
  237. Status = pRoot->LookupFolderByLogicalName( &LinkName,
  238. &Remaining,
  239. &pFolder );
  240. if(Status == ERROR_NOT_FOUND)
  241. {
  242. //see if it's a short name, in the short name
  243. //case, we have to calculate the remaining name
  244. //ourselves
  245. Status = pRoot->ExpandShortName(&LinkName,
  246. &LongName,
  247. &Remaining);
  248. if(Status == ERROR_SUCCESS)
  249. {
  250. //NotUsed just takes the place of Remaining
  251. //since it's really not used here
  252. Status = pRoot->LookupFolderByLogicalName( &LongName,
  253. &NotUsed,
  254. &pFolder );
  255. }
  256. pRoot->FreeShortNameData(&LongName);
  257. }
  258. }
  259. else {
  260. Status = ERROR_NOT_FOUND;
  261. }
  262. //
  263. // If no link was found beyond the root, we are interested
  264. // in the root folder itself. Return the root folder.
  265. // If we did find a link, we have a referenced link folder.
  266. // Release the root and we are done.
  267. //
  268. if (Status == ERROR_NOT_FOUND) {
  269. pFolder = pRoot;
  270. Remaining = LinkName;
  271. Status = ERROR_SUCCESS;
  272. }
  273. else {
  274. pRoot->ReleaseReference();
  275. }
  276. }
  277. if (Status == ERROR_SUCCESS) {
  278. *ppFolder = pFolder;
  279. *pRemainingName = Remaining;
  280. }
  281. DFS_TRACE_ERROR_NORM(Status, REFERRAL, "DfsLookupFolder Exit %x name %wZ\n",
  282. Status, pName);
  283. return Status;
  284. }
  285. //+-------------------------------------------------------------------------
  286. //
  287. // Function: DfsGetReferralData
  288. //
  289. // Arguments: pName - name we are interested in.
  290. // pRemainingName - the name that was unmatched.
  291. // ppReferralData - the referral data for the matching portion.
  292. //
  293. // Returns: ERROR_SUCCESS
  294. // error code otherwise
  295. //
  296. //
  297. // Description: This routine looks up the folder for the passed in name,
  298. // and loads the referral data for the folder and returns
  299. // a referenced FolderReferralData to the caller.
  300. //
  301. //--------------------------------------------------------------------------
  302. DFSSTATUS
  303. DfsGetReferralData(
  304. PUNICODE_STRING pName,
  305. PUNICODE_STRING pRemainingName,
  306. DfsFolderReferralData **ppReferralData,
  307. PBOOLEAN pCacheHit )
  308. {
  309. DFSSTATUS Status;
  310. DfsFolder *pFolder;
  311. BOOLEAN CacheHit = FALSE;
  312. DFS_TRACE_LOW( REFERRAL, "DfsGetReferralData Name %wZ\n", pName);
  313. Status = DfsLookupFolder( pName,
  314. pRemainingName,
  315. &pFolder );
  316. DFS_TRACE_ERROR_LOW( Status, REFERRAL, "get referral data, lookup folder %p, Status %x\n",
  317. pFolder, Status);
  318. if (Status == ERROR_SUCCESS) {
  319. Status = pFolder->GetReferralData( ppReferralData,
  320. &CacheHit );
  321. DFS_TRACE_LOW(REFERRAL, "Loaded %p Status %x\n", *ppReferralData, Status );
  322. pFolder->ReleaseReference();
  323. }
  324. if (pCacheHit != NULL)
  325. {
  326. *pCacheHit = CacheHit;
  327. }
  328. DFS_TRACE_ERROR_LOW( Status, REFERRAL, "DfsGetReferralData Name %wZ Status %x\n",
  329. pName, Status );
  330. return Status;
  331. }
  332. /*
  333. ULONG
  334. DfsGetInterSiteCost(
  335. PUNICODE_STRING pSiteFrom,
  336. PUNICODE_STRING pSiteTo)
  337. {
  338. ULONG Cost = 100;
  339. if ((IsEmptyString(pSiteFrom->Buffer) == FALSE) &&
  340. (IsEmptyString(pSiteTo->Buffer) == FALSE))
  341. {
  342. if (RtlEqualUnicodeString(pSiteFrom, pSiteTo, TRUE ))
  343. {
  344. Cost = 0;
  345. }
  346. }
  347. return Cost;
  348. }
  349. */
  350. VOID
  351. DfsShuffleReplicas(
  352. REPLICA_COST_INFORMATION * pReplicaCosts,
  353. ULONG nStart,
  354. ULONG nEnd)
  355. {
  356. ULONG i = 0;
  357. ULONG j = 0;
  358. ULONG nRemaining = 0;
  359. ULONG CostTemp = 0;
  360. LONG NewFactor = 0;
  361. DfsReplica * pTempReplica = NULL;
  362. LARGE_INTEGER Seed;
  363. for (i = nStart; i < nEnd; i++)
  364. {
  365. NtQuerySystemTime( &Seed );
  366. NewFactor = InterlockedIncrement(&ShuffleFudgeFactor);
  367. Seed.LowPart += (NewFactor + GetTickCount());
  368. DFS_TRACE_LOW(REFERRAL, "Shuffling %d to %d, seed %d (%x)\n",
  369. nStart, nEnd, Seed.LowPart, Seed.LowPart );
  370. //
  371. // Exchange the current entry with one in the remaining portion.
  372. // Make sure the entry doesn't get swapped with itself.
  373. //
  374. j = (RtlRandomEx( &Seed.LowPart ) % (nEnd - i)) + i;
  375. //
  376. // Give up.
  377. //
  378. if (j == i)
  379. {
  380. DFS_TRACE_LOW(REFERRAL_SERVER, "NOT Shuffling %d with %d\n",
  381. i, j);
  382. continue;
  383. }
  384. DFS_TRACE_LOW(REFERRAL_SERVER, "Shuffling %d with %d\n",
  385. i, j);
  386. CostTemp = (&pReplicaCosts[i])->ReplicaCost;
  387. pTempReplica = (&pReplicaCosts[i])->pReplica;
  388. (&pReplicaCosts[i])->pReplica = (&pReplicaCosts[j])->pReplica;
  389. (&pReplicaCosts[i])->ReplicaCost = (&pReplicaCosts[j])->ReplicaCost;
  390. (&pReplicaCosts[j])->pReplica = pTempReplica;
  391. (&pReplicaCosts[j])->ReplicaCost = CostTemp;
  392. }
  393. DFS_TRACE_LOW(REFERRAL, "Shuffling done\n");
  394. }
  395. VOID
  396. DfsSortReplicas(
  397. REPLICA_COST_INFORMATION * pReplicaCosts,
  398. ULONG NumReplicas)
  399. {
  400. LONG LoopVar = 0;
  401. LONG InnerLoop = 0;
  402. ULONG CostTemp = 0;
  403. DfsReplica * pTempReplica = NULL;
  404. for (LoopVar = 1; LoopVar < (LONG) NumReplicas; LoopVar++)
  405. {
  406. CostTemp = (&pReplicaCosts[LoopVar])->ReplicaCost;
  407. pTempReplica = (&pReplicaCosts[LoopVar])->pReplica;
  408. for(InnerLoop = LoopVar - 1; InnerLoop >= 0; InnerLoop--)
  409. {
  410. if((&pReplicaCosts[InnerLoop])->ReplicaCost > CostTemp)
  411. {
  412. (&pReplicaCosts[InnerLoop + 1])->ReplicaCost = (&pReplicaCosts[InnerLoop])->ReplicaCost;
  413. (&pReplicaCosts[InnerLoop + 1])->pReplica = (&pReplicaCosts[InnerLoop])->pReplica;
  414. }
  415. else
  416. {
  417. break;
  418. }
  419. }
  420. (&pReplicaCosts[InnerLoop + 1])->ReplicaCost = CostTemp;
  421. (&pReplicaCosts[InnerLoop + 1])->pReplica = pTempReplica;
  422. }
  423. }
  424. VOID
  425. DfsShuffleAndSortReferralInformation(
  426. PREFERRAL_INFORMATION pReferralInformation )
  427. {
  428. DfsShuffleReplicas( &pReferralInformation->ReplicaCosts[0], 0, pReferralInformation->NumberOfReplicas);
  429. DfsSortReplicas( &pReferralInformation->ReplicaCosts[0], pReferralInformation->NumberOfReplicas);
  430. }
  431. VOID
  432. DfsGetDefaultInterSiteCost(
  433. IN DfsSite *pReferralSite,
  434. IN DfsReplica *pReplica,
  435. OUT PULONG pCost)
  436. {
  437. pReferralSite->GetDefaultSiteCost( pReplica->GetSite(), pCost );
  438. return;
  439. }
  440. VOID
  441. DfsReleaseReferralInformation(
  442. PREFERRAL_INFORMATION pReferralInfo )
  443. {
  444. delete [] (PBYTE)(pReferralInfo);
  445. return NOTHING;
  446. }
  447. DFSSTATUS
  448. DfsGetDsInterSiteCost(
  449. IN DfsSite *pReferralSite,
  450. IN DfsReferralData *pReferralData,
  451. IN DfsReplica *pReplica,
  452. IN OUT PBOOLEAN pRetry,
  453. OUT PULONG pCost)
  454. {
  455. DFSSTATUS Status = ERROR_SUCCESS;
  456. BOOLEAN CostMatrixGenerated = *pRetry;
  457. BOOLEAN UseDefault = FALSE;
  458. DFSSTATUS RetStatus = ERROR_SUCCESS;
  459. //
  460. // Lookup the cost of going from the ReferralSite to the Replica Site
  461. // in our cache.
  462. //
  463. Status = pReferralSite->GetRealSiteCost( pReplica->GetSite(), pCost );
  464. // Try only once.
  465. if (CostMatrixGenerated)
  466. {
  467. *pRetry = FALSE;
  468. }
  469. // Ruminate over our choices based on what GetCost returned.
  470. do {
  471. if (Status == ERROR_SUCCESS)
  472. {
  473. // we are all set
  474. *pRetry = FALSE;
  475. break;
  476. }
  477. // We can get memory allocation failures at this point.
  478. if (CostMatrixGenerated || Status != ERROR_NOT_FOUND)
  479. {
  480. //
  481. // We've tried generating the inter-site cost once, but still
  482. // we haven't been able to find what we need. So use the default scheme.
  483. //
  484. UseDefault = TRUE;
  485. break;
  486. }
  487. // We try to generate the cost matrix at most once per referral.
  488. // This is the first time around.
  489. ASSERT(Status == ERROR_NOT_FOUND);
  490. ASSERT(CostMatrixGenerated == FALSE);
  491. Status = pReferralData->GenerateCostMatrix( pReferralSite );
  492. //
  493. // If our call to the DS failed, then we just have to fall back on our default.
  494. //
  495. if (Status != ERROR_SUCCESS)
  496. {
  497. UseDefault = TRUE;
  498. RetStatus = Status;
  499. break;
  500. }
  501. // Caller needs to iterate over all the referrals again.
  502. *pRetry = TRUE;
  503. } while (FALSE);
  504. //
  505. // Somehow we haven't been able to find the real inter-site cost.
  506. // Use the default cost. This call won't fail.
  507. //
  508. if (UseDefault)
  509. {
  510. *pRetry = FALSE;
  511. pReferralSite->GetDefaultSiteCost( pReplica->GetSite(), pCost );
  512. }
  513. //
  514. // The only errors that we propogate back are those we get from the DS.
  515. // They indicate that the cost matrix didn't get generated so we know not
  516. // to retry this call for all the link targets.
  517. //
  518. return RetStatus;
  519. }
  520. //+-------------------------------------------------------------------------
  521. //
  522. // Function: DfsGetReferralInformation
  523. //
  524. // Arguments: pReferralData - the referral data
  525. // NumReplicasToReturn - Number of replicas to return
  526. //
  527. // Returns: ERROR_SUCCESS
  528. // ERROR_NOT_ENOUGH_MEMORY
  529. //
  530. //
  531. // Description: This routine generates the cost of reaching each replica
  532. //
  533. //
  534. //
  535. //--------------------------------------------------------------------------
  536. DFSSTATUS
  537. DfsGetReferralInformation(
  538. PUNICODE_STRING pUseTargetServer,
  539. PUNICODE_STRING pUseFolder,
  540. DfsSite *pReferralSite,
  541. DfsReferralData *pReferralData,
  542. DWORD NumReplicasToReturn,
  543. ULONG CostLimit,
  544. PREFERRAL_INFORMATION *ppReferralInformation )
  545. {
  546. DFSSTATUS Status = ERROR_SUCCESS;
  547. ULONG NumReplicas = 0;
  548. ULONG TotalSize =0;
  549. ULONG SizeOfStrings = 0;
  550. ULONG Cost = 0;
  551. DfsReplica *pReplica = NULL;
  552. PREFERRAL_INFORMATION pReferralInfo = NULL;
  553. BOOLEAN IsSiteCostingEnabled = FALSE;
  554. BOOLEAN Retrying = FALSE;
  555. BOOLEAN DsErrorHit = FALSE;
  556. BOOLEAN DomainReplica = FALSE;
  557. //
  558. // Give out Insite referrals only, if we are not pointing to
  559. // an interlink with a single target (this is a clue to us that
  560. // this is a potential domain DFS, where insite does not make
  561. // sense)
  562. //
  563. if (pReferralData->IsOutOfDomain() && (pReferralData->ReplicaCount == 1))
  564. {
  565. pReplica = &pReferralData->pReplicas[ 0 ];
  566. if (pReplica->IsTargetAvailable())
  567. {
  568. PUNICODE_STRING pServer = NULL;
  569. DFSSTATUS DomainStatus = ERROR_SUCCESS;
  570. pServer = pReplica->GetTargetServer();
  571. DomainStatus = I_NetDfsIsThisADomainName(pServer->Buffer);
  572. if (DomainStatus == ERROR_SUCCESS)
  573. {
  574. DomainReplica = TRUE;
  575. }
  576. }
  577. }
  578. if (DomainReplica == FALSE)
  579. {
  580. if (pReferralData->IsRestrictToSite())
  581. {
  582. CostLimit = 0;
  583. }
  584. IsSiteCostingEnabled = pReferralData->DoSiteCosting;
  585. }
  586. //allocate the buffer
  587. TotalSize = sizeof(REFERRAL_INFORMATION) + (pReferralData->ReplicaCount * sizeof(REPLICA_COST_INFORMATION));
  588. pReferralInfo = (PREFERRAL_INFORMATION) new BYTE[TotalSize];
  589. DFS_TRACE_LOW(REFERRAL, "Client Site %wZ\n", pReferralSite->SiteName());
  590. if (pReferralInfo == NULL)
  591. {
  592. *ppReferralInformation = NULL;
  593. return ERROR_NOT_ENOUGH_MEMORY;
  594. }
  595. //
  596. // Make sure the site is ready to receive data. This means it is not
  597. // going to throw its SiteCostCache away while we are trying to add to it, or
  598. // read from it. This is a NO-OP when site costing is disabled.
  599. //
  600. pReferralSite->StartPrepareForCostGeneration( IsSiteCostingEnabled );
  601. do {
  602. RtlZeroMemory(pReferralInfo, TotalSize);
  603. pReferralInfo->pUseTargetServer = pUseTargetServer;
  604. pReferralInfo->pUseTargetFolder = pUseFolder;
  605. DsErrorHit = FALSE;
  606. for (NumReplicas = 0; NumReplicas < pReferralData->ReplicaCount; NumReplicas++)
  607. {
  608. pReplica = &pReferralData->pReplicas[ NumReplicas ];
  609. if (pReplica->IsTargetAvailable() == FALSE)
  610. {
  611. continue;
  612. }
  613. if (!IsSiteCostingEnabled || DsErrorHit)
  614. {
  615. // The cost is going to be either Zero or ULONG_MAX.
  616. DfsGetDefaultInterSiteCost(pReferralSite,
  617. pReplica,
  618. &Cost);
  619. ASSERT(Retrying == FALSE);
  620. ASSERT(Status == ERROR_SUCCESS);
  621. }
  622. else
  623. {
  624. //
  625. // Find the cost between the referral site and this potential destination replica.
  626. // If Site-Costing is turned on, we attempt to get the intersite cost from
  627. // our site-cost cache(s). If the information isn't cached we try to get the cost matrix
  628. // from an ISTG nearby. The protocol here is to RETRY this entire loop just once
  629. // if the DfsGetInterSiteCost call below returns Retrying = TRUE.
  630. //
  631. if (DfsGetDsInterSiteCost(pReferralSite,
  632. pReferralData,
  633. pReplica,
  634. &Retrying,
  635. &Cost) != ERROR_SUCCESS)
  636. {
  637. //
  638. // Remember the fact that we got an error trying to generate
  639. // the cost matrix. This way we won't try to do this DS call
  640. // for every replica. However, it is entirely possible for another
  641. // thread to try to generate the cost in the meantime.
  642. //
  643. DsErrorHit = TRUE;
  644. ASSERT(Retrying == FALSE);
  645. }
  646. //
  647. // If we don't find this, then we know we should retry.
  648. // So start this all over again.
  649. // We only retry once.
  650. //
  651. if (Retrying)
  652. {
  653. DFS_TRACE_LOW(REFERRAL, "Intersite cost for <%ws, %ws> not found. Retrying the referral\n",
  654. pReferralSite->SiteNameString(),
  655. pReplica->GetSite()->SiteNameString());
  656. break;
  657. }
  658. }
  659. DFS_TRACE_LOW(REFERRAL, "REplica %wZ, Inter site <%ws, %ws> Cost %d (Limit = %d)\n",
  660. pReplica->GetTargetServer(),
  661. pReferralSite->SiteNameString(),
  662. pReplica->GetSite()->SiteNameString(),
  663. Cost,
  664. CostLimit);
  665. if (Cost <= CostLimit)
  666. {
  667. PUNICODE_STRING pTargetServer = (pUseTargetServer == NULL)? pReplica->GetTargetServer() : pUseTargetServer;
  668. PUNICODE_STRING pTargetFolder = (pUseFolder == NULL) ? pReplica->GetTargetFolder() : pUseFolder;
  669. pReferralInfo->ReplicaCosts[pReferralInfo->NumberOfReplicas].ReplicaCost = Cost;
  670. pReferralInfo->ReplicaCosts[pReferralInfo->NumberOfReplicas].pReplica = pReplica;
  671. SizeOfStrings = (sizeof(UNICODE_PATH_SEP) +
  672. pTargetServer->Length +
  673. sizeof(UNICODE_PATH_SEP) +
  674. pTargetFolder->Length );
  675. SizeOfStrings = ROUND_UP_COUNT(SizeOfStrings, ALIGN_LONG);
  676. pReferralInfo->TotalReplicaStringLength += SizeOfStrings;
  677. pReferralInfo->NumberOfReplicas++;
  678. }
  679. }
  680. } while (Retrying);
  681. pReferralSite->EndPrepareForCostGeneration( IsSiteCostingEnabled );
  682. if (Status == ERROR_SUCCESS)
  683. {
  684. if (pReferralInfo->NumberOfReplicas > 1)
  685. {
  686. DfsShuffleAndSortReferralInformation( pReferralInfo );
  687. }
  688. if (pReferralInfo->NumberOfReplicas > NumReplicasToReturn)
  689. {
  690. pReferralInfo->NumberOfReplicas = NumReplicasToReturn;
  691. }
  692. *ppReferralInformation = pReferralInfo;
  693. {
  694. ULONG i;
  695. DFS_TRACE_LOW(REFERRAL, "Final Referral for Client Site %ws offline status is %ws\n", pReferralSite->SiteNameString(),
  696. (pReferralData->FolderOffLine == TRUE) ? L"OFFLINE":L"ONLINE" );
  697. for (i=0 ; i<pReferralInfo->NumberOfReplicas; i++)
  698. {
  699. DFS_TRACE_LOW(REFERRAL, "%d. Target %wZ, Site %ws, Cost %d\n",
  700. i,
  701. pReferralInfo->ReplicaCosts[i].pReplica->GetTargetServer(),
  702. pReferralInfo->ReplicaCosts[i].pReplica->GetSite()->SiteNameString(),
  703. pReferralInfo->ReplicaCosts[i].ReplicaCost);
  704. }
  705. }
  706. } else {
  707. DfsReleaseReferralInformation( pReferralInfo );
  708. *ppReferralInformation = NULL;
  709. }
  710. return Status;
  711. }
  712. //+-------------------------------------------------------------------------
  713. //
  714. // Function: DfsExtractReplicaData -
  715. //
  716. // Arguments: pReferralData - the referral data
  717. // NumReplicasToReturn - Number of replicas to return
  718. // CostLimit - maximum cost caller is willing to accept
  719. // Name - link name
  720. // pReplicaCosts - array of replicas with cost info
  721. // ppReferralHeader - address of buffer to accept replica info
  722. //
  723. // Returns: Status
  724. // ERROR_SUCCESS
  725. // ERROR_NOT_ENOUGH_MEMORY
  726. // others
  727. //
  728. //
  729. // Description: This routine formats the replicas into the format
  730. // the client expects. Which is a REFERRAL_HEADER followed
  731. // by an array of REPLICA_INFORMATIONs
  732. //
  733. //--------------------------------------------------------------------------
  734. DFSSTATUS
  735. DfsExtractReferralData(
  736. PUNICODE_STRING pName,
  737. PREFERRAL_INFORMATION pReferralInformation,
  738. REFERRAL_HEADER ** ppReferralHeader)
  739. {
  740. DFSSTATUS Status = ERROR_SUCCESS;
  741. ULONG NumReplicas = 0;
  742. ULONG TotalSize = 0;
  743. ULONG HeaderBaseLength = 0;
  744. ULONG BaseLength = 0;
  745. ULONG LinkNameLength = 0;
  746. PREFERRAL_HEADER pHeader = NULL;
  747. ULONG CurrentNameLength =0;
  748. ULONG CurrentEntryLength = 0;
  749. ULONG NextEntry = 0;
  750. DfsReplica *pReplica = NULL;
  751. PUNICODE_STRING pUseTargetFolder = pReferralInformation->pUseTargetFolder;
  752. PUNICODE_STRING pUseTargetServer = pReferralInformation->pUseTargetServer;
  753. PUCHAR ReferralBuffer = NULL;
  754. PUCHAR pReplicaBuffer = NULL;
  755. PWCHAR ReturnedName = NULL;
  756. PUNICODE_STRING pTargetServer = NULL;
  757. PUNICODE_STRING pTargetFolder = NULL;
  758. DFS_TRACE_LOW(REFERRAL, "Entering DfsExtractReferralData");
  759. //calculate size of header base structure
  760. HeaderBaseLength = FIELD_OFFSET( REFERRAL_HEADER, LinkName[0] );
  761. //calculate link name
  762. LinkNameLength = pName->Length;
  763. //calculate size of base replica structure
  764. BaseLength = FIELD_OFFSET( REPLICA_INFORMATION, ReplicaName[0] );
  765. //the total size of the data to be returned is the sum of all the
  766. //above calculated sizes
  767. TotalSize = ROUND_UP_COUNT((HeaderBaseLength + LinkNameLength), ALIGN_LONG) +
  768. (pReferralInformation->NumberOfReplicas * ROUND_UP_COUNT(BaseLength, ALIGN_LONG)) +
  769. pReferralInformation->TotalReplicaStringLength +
  770. sizeof(DWORD); // null termination at the end.
  771. //allocate the buffer
  772. ReferralBuffer = new BYTE[ TotalSize ];
  773. if (ReferralBuffer != NULL)
  774. {
  775. RtlZeroMemory( ReferralBuffer, TotalSize );
  776. pHeader = (PREFERRAL_HEADER) ReferralBuffer;
  777. pHeader->VersionNumber = CURRENT_DFS_REPLICA_HEADER_VERSION;
  778. pHeader->ReplicaCount = pReferralInformation->NumberOfReplicas;
  779. pHeader->OffsetToReplicas = ROUND_UP_COUNT((HeaderBaseLength + LinkNameLength), ALIGN_LONG);
  780. pHeader->LinkNameLength = LinkNameLength;
  781. pHeader->TotalSize = TotalSize;
  782. pHeader->ReferralFlags = 0;
  783. //copy the link name at the end of the header
  784. RtlCopyMemory(&ReferralBuffer[HeaderBaseLength], pName->Buffer, LinkNameLength);
  785. //place the replicas starting here
  786. pReplicaBuffer = (PUCHAR) ((PBYTE)ReferralBuffer + pHeader->OffsetToReplicas);
  787. //format the replicas in the output buffer
  788. for ( NumReplicas = 0; NumReplicas < pReferralInformation->NumberOfReplicas ; NumReplicas++ )
  789. {
  790. NextEntry += (ULONG)( CurrentEntryLength );
  791. pReplica = pReferralInformation->ReplicaCosts[NumReplicas].pReplica;
  792. pTargetServer = (pUseTargetServer == NULL) ? pReplica->GetTargetServer() : pUseTargetServer;
  793. pTargetFolder = (pUseTargetFolder == NULL) ? pReplica->GetTargetFolder() : pUseTargetFolder;
  794. CurrentNameLength = 0;
  795. ReturnedName = (PWCHAR) &pReplicaBuffer[NextEntry + BaseLength];
  796. //
  797. // Start with the leading path seperator
  798. //
  799. ReturnedName[ CurrentNameLength / sizeof(WCHAR) ] = UNICODE_PATH_SEP;
  800. CurrentNameLength += sizeof(UNICODE_PATH_SEP);
  801. //
  802. // next copy the server name.
  803. //
  804. RtlMoveMemory( &ReturnedName[ CurrentNameLength / sizeof(WCHAR) ],
  805. pTargetServer->Buffer,
  806. pTargetServer->Length);
  807. CurrentNameLength += pTargetServer->Length;
  808. if (pTargetFolder->Length > 0)
  809. {
  810. //
  811. // insert the unicode path seperator.
  812. //
  813. ReturnedName[ CurrentNameLength / sizeof(WCHAR) ] = UNICODE_PATH_SEP;
  814. CurrentNameLength += sizeof(UNICODE_PATH_SEP);
  815. RtlMoveMemory( &ReturnedName[ CurrentNameLength / sizeof(WCHAR) ],
  816. pTargetFolder->Buffer,
  817. pTargetFolder->Length);
  818. CurrentNameLength += pTargetFolder->Length;
  819. }
  820. ((PREPLICA_INFORMATION)&pReplicaBuffer[NextEntry])->ReplicaFlags = pReplica->GetReplicaFlags();
  821. ((PREPLICA_INFORMATION)&pReplicaBuffer[NextEntry])->ReplicaCost = pReferralInformation->ReplicaCosts[NumReplicas].ReplicaCost;
  822. ((PREPLICA_INFORMATION)&pReplicaBuffer[NextEntry])->ReplicaNameLength = CurrentNameLength;
  823. CurrentEntryLength = ROUND_UP_COUNT((CurrentNameLength + BaseLength), ALIGN_LONG);
  824. //setup the offset to the next entry
  825. *((PULONG)(&pReplicaBuffer[NextEntry])) = pHeader->OffsetToReplicas + NextEntry + CurrentEntryLength;
  826. }
  827. *((PULONG)(&pReplicaBuffer[NextEntry])) = 0;
  828. }
  829. else
  830. {
  831. Status = ERROR_NOT_ENOUGH_MEMORY;
  832. }
  833. if (Status == ERROR_SUCCESS)
  834. {
  835. *ppReferralHeader = pHeader;
  836. }
  837. DFS_TRACE_ERROR_HIGH(Status, REFERRAL, "Leaving DfsExtractReferralData, Status %x",
  838. Status);
  839. return Status;
  840. }
  841. DFSSTATUS
  842. DfsGenerateReferralFromData(
  843. PUNICODE_STRING pName,
  844. PUNICODE_STRING pUseTargetServer,
  845. PUNICODE_STRING pUseFolder,
  846. DfsSite *pSite,
  847. DfsReferralData *pReferralData,
  848. DWORD NumReplicasToReturn,
  849. ULONG CostLimit,
  850. REFERRAL_HEADER ** ppReferralHeader)
  851. {
  852. DFSSTATUS Status;
  853. REFERRAL_INFORMATION *pReferralInformation;
  854. //make sure the user doesn't over step his bounds
  855. if( (NumReplicasToReturn > pReferralData->ReplicaCount) ||
  856. (NumReplicasToReturn == 0) )
  857. {
  858. NumReplicasToReturn = pReferralData->ReplicaCount;
  859. }
  860. Status = DfsGetReferralInformation( pUseTargetServer,
  861. pUseFolder,
  862. pSite,
  863. pReferralData,
  864. NumReplicasToReturn,
  865. CostLimit,
  866. &pReferralInformation );
  867. if (Status == ERROR_SUCCESS)
  868. {
  869. Status = DfsExtractReferralData( pName,
  870. pReferralInformation,
  871. ppReferralHeader);
  872. if(Status == STATUS_SUCCESS)
  873. {
  874. (*ppReferralHeader)->Timeout = pReferralData->Timeout;
  875. }
  876. DfsReleaseReferralInformation( pReferralInformation );
  877. }
  878. return Status;
  879. }
  880. DFSSTATUS
  881. DfsGenerateADBlobReferral(
  882. PUNICODE_STRING pName,
  883. PUNICODE_STRING pShare,
  884. DfsSite *pReferralSite,
  885. DWORD NumReplicasToReturn,
  886. ULONG CostLimit,
  887. REFERRAL_HEADER ** ppReferralHeader)
  888. {
  889. DFSSTATUS Status;
  890. DfsReferralData *pReferralData;
  891. UNICODE_STRING ShareName;
  892. Status = DfsCreateUnicodeString( &ShareName, pShare );
  893. if (Status == ERROR_SUCCESS)
  894. {
  895. Status = DfsGetADRootReferralData( pName,
  896. &pReferralData );
  897. DfsFreeUnicodeString( &ShareName );
  898. if (Status == ERROR_SUCCESS)
  899. {
  900. Status = DfsGenerateReferralFromData( pName,
  901. NULL,
  902. NULL,
  903. pReferralSite,
  904. pReferralData,
  905. NumReplicasToReturn,
  906. CostLimit,
  907. ppReferralHeader );
  908. if (Status == ERROR_SUCCESS)
  909. {
  910. (*ppReferralHeader)->ReferralFlags |= DFS_REFERRAL_DATA_ROOT_REFERRAL;
  911. }
  912. pReferralData->ReleaseReference();
  913. }
  914. }
  915. return Status;
  916. }
  917. DFSSTATUS
  918. DfsGenerateDomainDCReferral(
  919. PUNICODE_STRING pDomainName,
  920. DfsSite *pReferralSite,
  921. DWORD NumReplicasToReturn,
  922. ULONG CostLimit,
  923. REFERRAL_HEADER ** ppReferralHeader)
  924. {
  925. DFSSTATUS Status = ERROR_SUCCESS;
  926. DfsReferralData *pReferralData = NULL;
  927. BOOLEAN CacheHit;
  928. DfsDomainInformation *pDomainInfo;
  929. DFS_TRACE_LOW( REFERRAL, "DfsGenerateDomainDcReferral for Domain %wZ\n",
  930. pDomainName);
  931. Status = DfsAcquireDomainInfo( &pDomainInfo );
  932. if (Status == ERROR_SUCCESS)
  933. {
  934. Status = pDomainInfo->GetDomainDcReferralInfo( pDomainName,
  935. &pReferralData,
  936. &CacheHit );
  937. DfsReleaseDomainInfo (pDomainInfo );
  938. }
  939. if (Status == ERROR_SUCCESS)
  940. {
  941. Status = DfsGenerateReferralFromData( pDomainName,
  942. NULL,
  943. NULL,
  944. pReferralSite,
  945. pReferralData,
  946. NumReplicasToReturn,
  947. CostLimit,
  948. ppReferralHeader );
  949. if (Status == ERROR_SUCCESS)
  950. {
  951. (*ppReferralHeader)->ReferralFlags |= DFS_REFERRAL_DATA_DOMAIN_DC_REFERRAL;
  952. }
  953. pReferralData->ReleaseReference();
  954. }
  955. return Status;
  956. }
  957. DFSSTATUS
  958. DfsGenerateNormalReferral(
  959. LPWSTR LinkName,
  960. DfsSite *pSite,
  961. DWORD NumReplicasToReturn,
  962. ULONG CostLimit,
  963. REFERRAL_HEADER ** ppReferralHeader)
  964. {
  965. DFSSTATUS Status = ERROR_SUCCESS;
  966. DfsFolderReferralData *pReferralData = NULL;
  967. BOOLEAN CacheHit = TRUE;
  968. DFSSTATUS GetStatus = ERROR_SUCCESS;
  969. PUNICODE_STRING pUseTargetServer = NULL;
  970. UNICODE_STRING ServerComponent, ShareComponent, RemainingName;
  971. DfsRootFolder *pRoot = NULL;
  972. UNICODE_STRING LinkRemains;
  973. UNICODE_STRING Name, Remaining;
  974. ULONG StartTime, EndTime;
  975. DFS_TRACE_LOW( REFERRAL, "DfsGenerateReferral for Link %ws\n",
  976. LinkName);
  977. DfsGetTimeStamp( &StartTime );
  978. Status = DfsRtlInitUnicodeStringEx(&Name, LinkName);
  979. if (Status != ERROR_SUCCESS)
  980. {
  981. goto done;
  982. }
  983. Status = DfsGetReferralData( &Name,
  984. &Remaining,
  985. &pReferralData,
  986. &CacheHit );
  987. //
  988. // DFSDEV: this is necessary to support clusters: the api request will
  989. // neveer come to the dfs server when the VS name has failed.
  990. // The cluster service retries the api request with the machine name,
  991. // the dfs api still goes to the vs name due to the way we pack the
  992. // referral: this special cases clusters.
  993. // if the request comes in with a machine name, return the machine
  994. // name.
  995. //
  996. if ((Status == ERROR_SUCCESS) &&
  997. DfsIsMachineCluster())
  998. {
  999. Status = DfsGetPathComponents( &Name,
  1000. &ServerComponent,
  1001. &ShareComponent,
  1002. &RemainingName );
  1003. if ((Status == ERROR_SUCCESS) &&
  1004. (RemainingName.Length == 0))
  1005. {
  1006. UNICODE_STRING MachineName;
  1007. Status = DfsGetMachineName( &MachineName );
  1008. if (Status == ERROR_SUCCESS)
  1009. {
  1010. if ( (ServerComponent.Length == MachineName.Length) &&
  1011. (_wcsnicmp( ServerComponent.Buffer,
  1012. MachineName.Buffer,
  1013. MachineName.Length/sizeof(WCHAR)) == 0) )
  1014. {
  1015. pUseTargetServer = &ServerComponent;
  1016. }
  1017. DfsReleaseMachineName( &MachineName);
  1018. }
  1019. }
  1020. }
  1021. if (Status == ERROR_SUCCESS)
  1022. {
  1023. Name.Length -= Remaining.Length;
  1024. if (Name.Length && (Name.Buffer[(Name.Length/sizeof(WCHAR)) - 1] == UNICODE_PATH_SEP))
  1025. {
  1026. Name.Length -= sizeof(WCHAR);
  1027. }
  1028. Status = DfsGenerateReferralFromData( &Name,
  1029. pUseTargetServer,
  1030. NULL,
  1031. pSite,
  1032. pReferralData,
  1033. NumReplicasToReturn,
  1034. CostLimit,
  1035. ppReferralHeader);
  1036. if (Status == ERROR_SUCCESS)
  1037. {
  1038. if (pReferralData->IsRootReferral())
  1039. {
  1040. (*ppReferralHeader)->ReferralFlags |= DFS_REFERRAL_DATA_ROOT_REFERRAL;
  1041. }
  1042. if (pReferralData->IsOutOfDomain())
  1043. {
  1044. (*ppReferralHeader)->ReferralFlags |= DFS_REFERRAL_DATA_OUT_OF_DOMAIN;
  1045. }
  1046. }
  1047. pReferralData->ReleaseReference();
  1048. }
  1049. DfsGetTimeStamp( &EndTime );
  1050. //
  1051. // Get a root folder
  1052. //
  1053. GetStatus = DfsGetRootFolder( &Name,
  1054. &LinkRemains,
  1055. &pRoot );
  1056. if (GetStatus == ERROR_SUCCESS)
  1057. {
  1058. pRoot->pStatistics->UpdateReferralStat( CacheHit,
  1059. EndTime - StartTime,
  1060. Status );
  1061. pRoot->ReleaseReference();
  1062. }
  1063. done:
  1064. DFS_TRACE_ERROR_HIGH( Status, REFERRAL, "DfsGenerateReferral for Link %ws CacheHit %d Status %x\n",
  1065. LinkName, CacheHit, Status);
  1066. return Status;
  1067. }
  1068. DFSSTATUS
  1069. DfsGenerateSpecialShareReferral(
  1070. PUNICODE_STRING pName,
  1071. PUNICODE_STRING pDomainName,
  1072. PUNICODE_STRING pShareName,
  1073. DfsSite *pSite,
  1074. DWORD NumReplicasToReturn,
  1075. ULONG CostLimit,
  1076. REFERRAL_HEADER ** ppReferralHeader)
  1077. {
  1078. DFSSTATUS Status = ERROR_SUCCESS;
  1079. DfsReferralData *pReferralData = NULL;
  1080. BOOLEAN CacheHit;
  1081. DfsDomainInformation *pDomainInfo;
  1082. DFS_TRACE_LOW( REFERRAL, "DfsGenerateDomainDcReferral for Domain %wZ\n",
  1083. pDomainName);
  1084. Status = DfsAcquireDomainInfo( &pDomainInfo );
  1085. if (Status == ERROR_SUCCESS)
  1086. {
  1087. Status = pDomainInfo->GetDomainDcReferralInfo( pDomainName,
  1088. &pReferralData,
  1089. &CacheHit );
  1090. DfsReleaseDomainInfo (pDomainInfo );
  1091. }
  1092. if (Status == ERROR_SUCCESS)
  1093. {
  1094. Status = DfsGenerateReferralFromData( pName,
  1095. NULL,
  1096. pShareName,
  1097. pSite,
  1098. pReferralData,
  1099. NumReplicasToReturn,
  1100. CostLimit,
  1101. ppReferralHeader );
  1102. //
  1103. // Do not enable this ROOT_REFERRAL for special shares.
  1104. // These are not treated as normal DFS shares, and for compat
  1105. // purposes, it is necessary that this flag be turned off.
  1106. //
  1107. //
  1108. // if (Status == ERROR_SUCCESS) {
  1109. // (*ppReferralHeader)->ReferralFlags |= DFS_REFERRAL_DATA_ROOT_REFERRAL;
  1110. // }
  1111. pReferralData->ReleaseReference();
  1112. }
  1113. return Status;
  1114. }
  1115. DFSSTATUS
  1116. DfsGenerateDcReferral(
  1117. LPWSTR LinkNameString,
  1118. DfsSite *pReferralSite,
  1119. DWORD NumReplicasToReturn,
  1120. ULONG CostLimit,
  1121. REFERRAL_HEADER ** ppReferralHeader)
  1122. {
  1123. DFSSTATUS Status = ERROR_SUCCESS;
  1124. DfsDomainInformation *pDomainInfo = NULL;
  1125. UNICODE_STRING NameContext;
  1126. UNICODE_STRING ShareName;
  1127. UNICODE_STRING RemainingName;
  1128. UNICODE_STRING LinkName;
  1129. Status = DfsRtlInitUnicodeStringEx( &LinkName, LinkNameString );
  1130. if (Status != ERROR_SUCCESS)
  1131. {
  1132. goto done;
  1133. }
  1134. RtlInitUnicodeString(&NameContext, NULL);
  1135. if (LinkName.Length > 0)
  1136. {
  1137. Status = DfsGetPathComponents( &LinkName,
  1138. &NameContext,
  1139. &ShareName,
  1140. &RemainingName );
  1141. }
  1142. if (Status == ERROR_SUCCESS)
  1143. {
  1144. if (NameContext.Length == 0)
  1145. {
  1146. Status = DfsAcquireDomainInfo( &pDomainInfo );
  1147. if (Status == ERROR_SUCCESS)
  1148. {
  1149. Status = pDomainInfo->GenerateDomainReferral( ppReferralHeader );
  1150. DfsReleaseDomainInfo( pDomainInfo );
  1151. }
  1152. }
  1153. else if (ShareName.Length == 0)
  1154. {
  1155. Status = DfsGenerateDomainDCReferral( &NameContext,
  1156. pReferralSite,
  1157. NumReplicasToReturn,
  1158. CostLimit,
  1159. ppReferralHeader );
  1160. }
  1161. else if ( (RemainingName.Length == 0) )
  1162. //
  1163. // Commenting out the rest of the IF statement for win9x
  1164. // compatibility.
  1165. // (DfsIsNameContextDomainName(&NameContext)) )
  1166. //
  1167. {
  1168. if (DfsIsSpecialDomainShare(&ShareName))
  1169. {
  1170. Status = DfsGenerateSpecialShareReferral( &LinkName,
  1171. &NameContext,
  1172. &ShareName,
  1173. pReferralSite,
  1174. NumReplicasToReturn,
  1175. CostLimit,
  1176. ppReferralHeader );
  1177. }
  1178. else
  1179. {
  1180. Status = DfsGenerateADBlobReferral( &LinkName,
  1181. &ShareName,
  1182. pReferralSite,
  1183. NumReplicasToReturn,
  1184. CostLimit,
  1185. ppReferralHeader );
  1186. }
  1187. if (Status != ERROR_SUCCESS)
  1188. {
  1189. if (DfsIsNameContextDomainName(&NameContext) == FALSE)
  1190. {
  1191. Status = ERROR_NOT_FOUND;
  1192. }
  1193. }
  1194. }
  1195. else
  1196. {
  1197. Status = ERROR_NOT_FOUND;
  1198. }
  1199. }
  1200. done:
  1201. return Status;
  1202. }
  1203. //+-------------------------------------------------------------------------
  1204. //
  1205. // Function: GetReplicaData -
  1206. //
  1207. // Arguments: LinkName - pointer to link name
  1208. // Sitename - pointer to site name.
  1209. // NumReplicasToReturn - Number of replicas to return
  1210. // CostLimit - maximum cost caller is willing to accept
  1211. // ppReferralHeader - address of buffer to accept replica info
  1212. //
  1213. // Returns: Status
  1214. // ERROR_SUCCESS
  1215. // ERROR_NOT_ENOUGH_MEMORY
  1216. // others
  1217. //
  1218. //
  1219. // Description: This routine extracts the replicas from the referral
  1220. //
  1221. //--------------------------------------------------------------------------
  1222. DFSSTATUS
  1223. DfsGenerateReferral(
  1224. LPWSTR LinkName,
  1225. DfsSite *pReferralSite,
  1226. DWORD NumReplicasToReturn,
  1227. ULONG CostLimit,
  1228. REFERRAL_HEADER ** ppReferralHeader)
  1229. {
  1230. DFSSTATUS Status;
  1231. //
  1232. // First check if this machine is a DC. If it is, it has special
  1233. // responsibility in the referral process. Check if it needs to
  1234. // provide a referral as a DC.
  1235. //
  1236. //
  1237. if (DfsIsMachineDC())
  1238. {
  1239. Status = DfsGenerateDcReferral( LinkName,
  1240. pReferralSite,
  1241. NumReplicasToReturn,
  1242. CostLimit,
  1243. ppReferralHeader );
  1244. if (Status != ERROR_NOT_FOUND)
  1245. {
  1246. return Status;
  1247. }
  1248. }
  1249. //
  1250. // If we are here, we are either an ordinary machine or a DC
  1251. // and this referral is not a DC type referral.
  1252. // Try to treat this machine as a normal machine, and generate a
  1253. // referral based on what this machine knows about.
  1254. //
  1255. Status = DfsGenerateNormalReferral( LinkName,
  1256. pReferralSite,
  1257. NumReplicasToReturn,
  1258. CostLimit,
  1259. ppReferralHeader );
  1260. //
  1261. // if we still failed, and we are a DC, it is possible that a old
  1262. // win9x client is coming in and we try to generate a referral
  1263. // for compat.
  1264. //
  1265. if ((DfsIsMachineDC()) &&
  1266. (Status != ERROR_SUCCESS))
  1267. {
  1268. DFSSTATUS CompatStatus;
  1269. CompatStatus = DfsGenerateCompatReferral( LinkName,
  1270. pReferralSite,
  1271. ppReferralHeader );
  1272. if (CompatStatus == ERROR_SUCCESS)
  1273. {
  1274. Status = CompatStatus;
  1275. }
  1276. }
  1277. return Status;
  1278. }
  1279. VOID
  1280. DfsReleaseReferral(
  1281. REFERRAL_HEADER *pReferralHeader)
  1282. {
  1283. delete [] (PBYTE)pReferralHeader;
  1284. }
  1285. DFSSTATUS
  1286. DfsGenerateCompatReferral(
  1287. LPWSTR LinkName,
  1288. DfsSite *pReferralSite,
  1289. REFERRAL_HEADER ** ppReferralHeader)
  1290. {
  1291. DFSSTATUS Status = ERROR_SUCCESS;
  1292. DfsFolderReferralData *pReferralData = NULL;
  1293. BOOLEAN CacheHit = TRUE;
  1294. UNICODE_STRING Name, Remaining;
  1295. DFS_TRACE_LOW( REFERRAL, "DfsGenerateCompatReferral for Link %ws\n",
  1296. LinkName);
  1297. Status = DfsRtlInitUnicodeStringEx(&Name, LinkName);
  1298. if (Status != ERROR_SUCCESS)
  1299. {
  1300. goto done;
  1301. }
  1302. Status = DfsGetCompatReferralData( &Name,
  1303. &Remaining,
  1304. &pReferralData,
  1305. &CacheHit );
  1306. if (Status == ERROR_SUCCESS)
  1307. {
  1308. Name.Length -= Remaining.Length;
  1309. if (Name.Length && (Name.Buffer[(Name.Length/sizeof(WCHAR)) - 1] == UNICODE_PATH_SEP))
  1310. {
  1311. Name.Length -= sizeof(WCHAR);
  1312. }
  1313. Status = DfsGenerateReferralFromData( &Name,
  1314. NULL,
  1315. NULL,
  1316. pReferralSite,
  1317. pReferralData,
  1318. 1000,
  1319. DFS_MAX_COST,
  1320. ppReferralHeader);
  1321. pReferralData->ReleaseReference();
  1322. }
  1323. done:
  1324. DFS_TRACE_ERROR_HIGH( Status, REFERRAL, "DfsGenerateCompatReferral for Link %ws CacheHit %d Status %x\n",
  1325. LinkName, CacheHit, Status);
  1326. return Status;
  1327. }