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.

801 lines
26 KiB

  1. #include "DfsGeneric.hxx"
  2. #include "dsgetdc.h"
  3. #include "dsrole.h"
  4. #include "DfsDomainInformation.hxx"
  5. #include "DfsTrustedDomain.hxx"
  6. #include "DfsReferralData.hxx"
  7. #include "DomainControllerSupport.hxx"
  8. #include "DfsReplica.hxx"
  9. #include "dfsadsiapi.hxx"
  10. #include "lmdfs.h"
  11. #include "dfserror.hxx"
  12. #include "dfsfilterapi.hxx"
  13. #include "DomainControllerSupport.tmh"
  14. #define RemoteServerNameString L"remoteServerName"
  15. extern
  16. DFS_SERVER_GLOBAL_DATA DfsServerGlobalData;
  17. #define HRESULT_TO_DFSSTATUS(_x) (_x)
  18. DFSSTATUS
  19. DfsDcInit(
  20. PBOOLEAN pIsDc )
  21. {
  22. PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pPrimaryDomainInfo = NULL;
  23. DFSSTATUS Status = ERROR_SUCCESS;
  24. HANDLE hThread;
  25. DWORD idThread;
  26. Status = DsRoleGetPrimaryDomainInformation( NULL,
  27. DsRolePrimaryDomainInfoBasic,
  28. (PBYTE *)&pPrimaryDomainInfo);
  29. if (Status == ERROR_SUCCESS)
  30. {
  31. #if defined (DC_TESTING)
  32. pPrimaryDomainInfo->MachineRole = DsRole_RoleBackupDomainController;
  33. #endif
  34. if(pPrimaryDomainInfo->MachineRole == DsRole_RoleStandaloneServer)
  35. {
  36. DfsServerGlobalData.IsWorkGroup = TRUE;
  37. }
  38. else
  39. {
  40. DfsServerGlobalData.IsWorkGroup = FALSE;
  41. }
  42. if ( (pPrimaryDomainInfo->MachineRole == DsRole_RoleBackupDomainController) ||
  43. (pPrimaryDomainInfo->MachineRole == DsRole_RolePrimaryDomainController) )
  44. {
  45. *pIsDc = TRUE;
  46. hThread = CreateThread( NULL, //Security attributes
  47. 0, //Use default stack size
  48. DcUpdateLoop, // Thread entry procedure
  49. 0, // Thread context parameter
  50. 0, // Start immediately
  51. &idThread); // Thread ID
  52. if (hThread == NULL)
  53. {
  54. //
  55. // log this
  56. //
  57. Status = GetLastError();
  58. }
  59. else
  60. {
  61. CloseHandle(hThread);
  62. }
  63. }
  64. DfsSetDomainNameFlat( pPrimaryDomainInfo->DomainNameFlat);
  65. DfsSetDomainNameDns( pPrimaryDomainInfo->DomainNameDns);
  66. DsRoleFreeMemory(pPrimaryDomainInfo);
  67. }
  68. return Status;
  69. }
  70. #define DC_PERIODIC_UPDATE_INTERVAL (1000 * 60 * 10) // 10 minutes
  71. DWORD
  72. DcUpdateLoop(
  73. LPVOID lpThreadParams)
  74. {
  75. UNREFERENCED_PARAMETER(lpThreadParams);
  76. DFSSTATUS Status;
  77. DfsDomainInformation *pDomainInfo;
  78. LONG InitialRetry = 10;
  79. ULONG SleepTime = 1000 * 15; // 15 seconds.
  80. static ULONG DomainRefreshFixedInterval;
  81. static ULONG DomainRefreshIntervalOnError;
  82. ULONG DomainRefreshTime;
  83. // Default is 72 update intervals -> 12 hrs
  84. DomainRefreshFixedInterval = (DfsServerGlobalData.DomainNameRefreshInterval / (DC_PERIODIC_UPDATE_INTERVAL / 1000));
  85. // On enumeration errors, one hour (1/12th the time of domain-name-refresh-interval) is a better time to wait.
  86. DomainRefreshIntervalOnError = DomainRefreshFixedInterval/12;
  87. if (DomainRefreshFixedInterval == 0)
  88. {
  89. DomainRefreshFixedInterval = 1;
  90. }
  91. if (DomainRefreshIntervalOnError == 0)
  92. {
  93. DomainRefreshIntervalOnError = 1;
  94. }
  95. pDomainInfo = NULL;
  96. Status = GetDomainInformation(&pDomainInfo);
  97. //
  98. // It's possible to get only a part of the domain information because of an error
  99. // (typically because the DC discovery failed). In that case we have a Status != ERROR_SUCCESS here,
  100. // but still have a valid DomainInfo.
  101. //
  102. if (pDomainInfo != NULL)
  103. {
  104. DfsSetGlobalDomainInfo(pDomainInfo);
  105. pDomainInfo->ReleaseReference();
  106. pDomainInfo = NULL;
  107. }
  108. while ( (Status != ERROR_SUCCESS) &&
  109. (InitialRetry-- > 0) )
  110. {
  111. WaitForSingleObject(DfsServerGlobalData.ShutdownHandle, SleepTime);
  112. if (DfsIsShuttingDown())
  113. {
  114. goto Exit;
  115. }
  116. Status = GetDomainInformation(&pDomainInfo);
  117. if (pDomainInfo != NULL)
  118. {
  119. DfsSetGlobalDomainInfo(pDomainInfo);
  120. pDomainInfo->ReleaseReference();
  121. pDomainInfo = NULL;
  122. }
  123. DFS_TRACE_LOW(REFERRAL_SERVER, "startup Updating Domain info...%p, %x\n", pDomainInfo,Status);
  124. }
  125. SleepTime = DC_PERIODIC_UPDATE_INTERVAL;
  126. DomainRefreshTime = DomainRefreshFixedInterval;
  127. do {
  128. WaitForSingleObject(DfsServerGlobalData.ShutdownHandle, SleepTime);
  129. if (DfsIsShuttingDown())
  130. {
  131. break;
  132. }
  133. //
  134. // every so often, throw away our entire domain information
  135. // and rebuild.
  136. // Every 10 minutes, purge our DC information.
  137. //
  138. //
  139. if (--DomainRefreshTime == 0)
  140. {
  141. Status = GetDomainInformation(&pDomainInfo);
  142. DFS_TRACE_LOW(REFERRAL_SERVER, "DcUpdateLoop: Updating Domain info...%p, %x\n", pDomainInfo,Status);
  143. // It'll be 12 * 6 more update-intervals for the next enumeration if everythings working well.
  144. // Otherwise it's 6.
  145. if (Status == ERROR_SUCCESS)
  146. {
  147. DomainRefreshTime = DomainRefreshFixedInterval; // 72 update intervals = 12 hrs by default.
  148. }
  149. else
  150. {
  151. DomainRefreshTime = DomainRefreshIntervalOnError; // 6 update intervals = 1 hr
  152. DFS_TRACE_HIGH(REFERRAL_SERVER, "DcUpdateLoop: Status 0x%x enumerating domains (info=%p), Resetting refresh time to %d mins\n",
  153. Status, pDomainInfo, DomainRefreshTime * SleepTime / 60000);
  154. }
  155. if (pDomainInfo != NULL)
  156. {
  157. DfsSetGlobalDomainInfo(pDomainInfo);
  158. pDomainInfo->ReleaseReference();
  159. pDomainInfo = NULL;
  160. }
  161. }
  162. else
  163. {
  164. Status = DfsAcquireDomainInfo(&pDomainInfo);
  165. DFS_TRACE_LOW(REFERRAL_SERVER, "DcUpdateLoop: Purging DC info...%p, %x\n", pDomainInfo,Status);
  166. if (Status == ERROR_SUCCESS)
  167. {
  168. pDomainInfo->PurgeDCReferrals();
  169. pDomainInfo->ReleaseReference();
  170. pDomainInfo = NULL;
  171. }
  172. }
  173. } while ( TRUE );
  174. Exit:
  175. return 0;
  176. }
  177. DFSSTATUS
  178. GetDomainInformation(
  179. DfsDomainInformation **ppDomainInfo )
  180. {
  181. DFSSTATUS Status = ERROR_SUCCESS;
  182. DFSSTATUS XforestStatus = ERROR_SUCCESS;
  183. *ppDomainInfo = NULL;
  184. DfsDomainInformation *pNewDomainInfo = new DfsDomainInformation( &Status, &XforestStatus );
  185. if (pNewDomainInfo == NULL)
  186. {
  187. Status = ERROR_NOT_ENOUGH_MEMORY;
  188. }
  189. else if (Status != ERROR_SUCCESS)
  190. {
  191. pNewDomainInfo->ReleaseReference();
  192. }
  193. if (Status == ERROR_SUCCESS)
  194. {
  195. *ppDomainInfo = pNewDomainInfo;
  196. //
  197. // Although we have a DomainInfo, our x-forest enumerations
  198. // may have failed. We go ahead, but we still let the caller know
  199. // that it needs to retry by sending the error status.
  200. //
  201. Status = XforestStatus;
  202. }
  203. return Status;
  204. }
  205. #if 0
  206. //+-------------------------------------------------------------------------
  207. //
  208. // Function: DfsGenerateReferralDataFromRemoteServerNames
  209. // IADs *pObject - the object
  210. // DfsfolderReferralData *pReferralData - the referral data
  211. //
  212. //
  213. // Returns: Status: Success or Error status code
  214. //
  215. // Description: This routine reads the remote server name
  216. // attribute and creates a referral data structure
  217. // so that we can pass a referral based on these names.
  218. //
  219. //--------------------------------------------------------------------------
  220. DFSSTATUS
  221. DfsGenerateReferralDataFromRemoteServerNames(
  222. LPWSTR RootName,
  223. DfsReferralData **ppReferralData )
  224. {
  225. HRESULT HResult = S_OK;
  226. BOOLEAN CacheHit = FALSE;
  227. DfsReplica *pReplicas = NULL;
  228. DFSSTATUS Status = ERROR_SUCCESS;
  229. DfsReferralData *pReferralData = NULL;
  230. IADs *pObject = NULL;
  231. VARIANT Variant;
  232. LPWSTR pszAttrs[] = { RemoteServerNameString };
  233. DWORD Number = sizeof(pszAttrs) / sizeof(LPWSTR);
  234. DFS_TRACE_HIGH( REFERRAL_SERVER, "Entering DfsGenerateReferralDataFromRemoteServerNames for RootName %ws\n",
  235. RootName);
  236. Status = DfsGetDfsRootADObject(NULL,
  237. RootName,
  238. &pObject );
  239. if (Status == ERROR_SUCCESS)
  240. {
  241. pReferralData = new DfsReferralData (&Status );
  242. if (pReferralData == NULL)
  243. {
  244. Status = ERROR_NOT_ENOUGH_MEMORY;
  245. }
  246. else if (Status != ERROR_SUCCESS)
  247. {
  248. pReferralData->ReleaseReference();
  249. }
  250. VariantInit( &Variant );
  251. //
  252. // Try to cache the RemoteServerNameString attribute locally,
  253. // if this fails, we dont care since we will be using the
  254. // GetEx call anyway.
  255. //
  256. if (Status == ERROR_SUCCESS)
  257. {
  258. HResult = ADsBuildVarArrayStr( pszAttrs, Number, &Variant);
  259. if ( SUCCEEDED(HResult))
  260. {
  261. HResult = pObject->GetInfoEx( Variant, 0);
  262. }
  263. VariantClear( &Variant);
  264. }
  265. if (Status == ERROR_SUCCESS)
  266. {
  267. LONG StartNdx, LastNdx;
  268. SAFEARRAY *PropertyArray;
  269. HResult = pObject->GetEx( RemoteServerNameString, &Variant );
  270. if ( SUCCEEDED(HResult) )
  271. {
  272. PropertyArray = V_ARRAY( &Variant );
  273. HResult = SafeArrayGetLBound( PropertyArray, 1, &StartNdx );
  274. if ( SUCCEEDED(HResult) )
  275. {
  276. HResult = SafeArrayGetUBound( PropertyArray, 1, &LastNdx );
  277. }
  278. }
  279. else
  280. {
  281. DFS_TRACE_HIGH(REFERRAL_SERVER, "DfsGenerateReferralDataFromRemoteServerNames-GetEx failed for RootName %ws with Status %x\n",
  282. RootName, HResult);
  283. }
  284. if ( SUCCEEDED(HResult) &&
  285. (LastNdx > StartNdx) )
  286. {
  287. VARIANT VariantItem;
  288. pReplicas = new DfsReplica [ LastNdx - StartNdx ];
  289. if (pReplicas != NULL)
  290. {
  291. for ( LONG Index = StartNdx; Index < LastNdx; Index++ )
  292. {
  293. VariantInit( &VariantItem );
  294. CacheHit = FALSE;
  295. HResult = SafeArrayGetElement( PropertyArray,
  296. &Index,
  297. &VariantItem );
  298. if ( SUCCEEDED(HResult) )
  299. {
  300. UNICODE_STRING ServerName, Remaining, Replica;
  301. LPWSTR ReplicaString = V_BSTR( &VariantItem );
  302. Status = DfsRtlInitUnicodeStringEx( &Replica, ReplicaString );
  303. if(Status == ERROR_SUCCESS)
  304. {
  305. DfsGetFirstComponent( &Replica,
  306. &ServerName,
  307. &Remaining );
  308. Status = (&pReplicas[ Index - StartNdx])->SetTargetServer( &ServerName, &CacheHit );
  309. if (Status == ERROR_SUCCESS)
  310. {
  311. Status = (&pReplicas[ Index - StartNdx])->SetTargetFolder( &Remaining );
  312. }
  313. }
  314. }
  315. else {
  316. Status = DfsGetErrorFromHr( HResult );
  317. DFS_TRACE_HIGH(REFERRAL_SERVER, "Leaving DfsGenerateReferralDataFromRemoteServerNames- SafeArrayGetElement for RootName %ws with Status %x\n",
  318. RootName, HResult);
  319. }
  320. VariantClear( &VariantItem );
  321. if (Status != ERROR_SUCCESS)
  322. {
  323. delete [] pReplicas;
  324. pReplicas = NULL;
  325. break;
  326. }
  327. }
  328. }
  329. else
  330. {
  331. Status = ERROR_NOT_ENOUGH_MEMORY;
  332. }
  333. }
  334. else
  335. {
  336. DFS_TRACE_HIGH(REFERRAL_SERVER, "DfsGenerateReferralDataFromRemoteServerNames- DfsGetDfsRootADObjectfailed for RootName %ws with Status %x\n",
  337. RootName, HResult);
  338. Status = DfsGetErrorFromHr( HResult );
  339. }
  340. VariantClear( &Variant );
  341. if (Status == ERROR_SUCCESS)
  342. {
  343. pReferralData->Timeout = DFS_DEFAULT_REFERRAL_TIMEOUT;
  344. pReferralData->ReplicaCount = LastNdx - StartNdx;
  345. pReferralData->pReplicas = pReplicas;
  346. *ppReferralData = pReferralData;
  347. }
  348. if (Status != ERROR_SUCCESS)
  349. {
  350. pReferralData->ReleaseReference();
  351. }
  352. }
  353. pObject->Release();
  354. }
  355. DFS_TRACE_ERROR_HIGH( Status, REFERRAL_SERVER, "Leaving DfsGenerateReferralDataFromRemoteServerNames for RootName %ws and Status %x\n",
  356. RootName, HResult);
  357. return Status;
  358. }
  359. #endif
  360. //+-------------------------------------------------------------------------
  361. //
  362. // Function: DfsUpdateRemoteServerName
  363. //
  364. // Arguments:
  365. // IADs *pObject - the ds object of interest.
  366. // LPWSTR ServerName - the server name to add or delete
  367. // LPWSTR RemainingName - the rest of the name
  368. // BOOLEAN Add - true for add, false for delete.
  369. //
  370. // Returns: Status: Success or Error status code
  371. //
  372. // Description: This routine updates the RemoteServerName attribute
  373. // in the DS object, either adding a \\servername\remaining
  374. // to the existing DS attribute or removing it, depending
  375. // on add/delete.
  376. // The caller must make sure this parameter does not
  377. // already exist in the add case, or that the parameter
  378. // to be deleted does exist in the delete case.
  379. //
  380. //--------------------------------------------------------------------------
  381. DFSSTATUS
  382. DfsUpdateRemoteServerName(
  383. IADs *pObject,
  384. LPWSTR ServerName,
  385. LPWSTR RemainingName,
  386. BOOLEAN Add )
  387. {
  388. HRESULT HResult = S_OK;
  389. DFSSTATUS Status = ERROR_SUCCESS;
  390. VARIANT Variant;
  391. UNICODE_STRING UpdateName;
  392. LPWSTR pServers[1];
  393. BSTR RemoteServerNameBstr;
  394. RemoteServerNameBstr = SysAllocString(RemoteServerNameString);
  395. if (RemoteServerNameBstr == NULL)
  396. {
  397. return ERROR_NOT_ENOUGH_MEMORY;
  398. }
  399. DFS_TRACE_HIGH( REFERRAL_SERVER, "Entering DfsUpdateRemoteServerName for ServerName %ws, remaining name %ws, add %d\n",
  400. ServerName, RemainingName, Add);
  401. //
  402. // create a unc path using the server and remaining name
  403. // to get a path of type \\servername\remainingname
  404. //
  405. Status = DfsCreateUnicodePathString( &UpdateName,
  406. 2, // unc path: 2 leading seperators,
  407. ServerName,
  408. RemainingName);
  409. pServers[0] = UpdateName.Buffer;
  410. if (Status == ERROR_SUCCESS)
  411. {
  412. //
  413. // initialize the variant.
  414. //
  415. VariantInit( &Variant );
  416. //
  417. // Create the variant array with a single entry in it.
  418. //
  419. HResult = ADsBuildVarArrayStr( pServers,
  420. 1,
  421. &Variant );
  422. if ( SUCCEEDED(HResult) )
  423. {
  424. //
  425. // either append or delete this string from the remote server
  426. // name attribute
  427. //
  428. HResult = pObject->PutEx( (Add ? ADS_PROPERTY_APPEND : ADS_PROPERTY_DELETE),
  429. RemoteServerNameBstr,
  430. Variant );
  431. if ( SUCCEEDED(HResult) )
  432. {
  433. //
  434. // now update the object in the DS with this info.
  435. //
  436. HResult = pObject->SetInfo();
  437. }
  438. //
  439. // clear the variant
  440. //
  441. VariantClear( &Variant );
  442. }
  443. if ( SUCCEEDED(HResult) == FALSE)
  444. {
  445. Status = DfsGetErrorFromHr( HResult );
  446. }
  447. //
  448. // free the unicode string we created earlier on.
  449. //
  450. DfsFreeUnicodeString( &UpdateName );
  451. }
  452. SysFreeString(RemoteServerNameBstr);
  453. DFS_TRACE_ERROR_HIGH( Status, REFERRAL_SERVER, "Leaving DfsUpdateRemoteServerName ServerName %ws, RemainingName %ws, Add %d, and Status %x\n",
  454. ServerName, RemainingName, Add, HResult);
  455. return Status;
  456. }
  457. DFSSTATUS
  458. DfsDcEnumerateRoots(
  459. LPWSTR DfsName,
  460. LPBYTE pBuffer,
  461. ULONG BufferSize,
  462. PULONG pEntriesRead,
  463. DWORD MaxEntriesToRead,
  464. LPDWORD pResumeHandle,
  465. PULONG pSizeRequired )
  466. {
  467. DFSSTATUS Status = ERROR_SUCCESS;
  468. DFSSTATUS PDCStatus;
  469. ULONG_PTR CurrentBuffer = (ULONG_PTR)pBuffer;
  470. ULONG CurrentSize = BufferSize;
  471. DfsString *pPDCName = NULL;
  472. LPWSTR UseDC = NULL;
  473. UNREFERENCED_PARAMETER(DfsName);
  474. PDCStatus = DfsGetBlobPDCName( &pPDCName, 0 );
  475. if (PDCStatus == ERROR_SUCCESS)
  476. {
  477. UseDC = pPDCName->GetString();
  478. //
  479. // At this point we dont care: if we got a dc name use it,
  480. // otherwise, just keep going, we will go to the local dc.
  481. //
  482. Status = DfsEnumerateDfsADRoots( UseDC,
  483. &CurrentBuffer,
  484. &CurrentSize,
  485. pEntriesRead,
  486. MaxEntriesToRead,
  487. pResumeHandle,
  488. pSizeRequired );
  489. DfsReleaseBlobPDCName(pPDCName);
  490. }
  491. return Status;
  492. }
  493. DFSSTATUS
  494. DfsUpdateRootRemoteServerName(
  495. LPWSTR Root,
  496. LPWSTR DCName,
  497. LPWSTR ServerName,
  498. LPWSTR RemainingName,
  499. BOOLEAN Add )
  500. {
  501. IADs *pRootObject = NULL;
  502. DFSSTATUS Status = ERROR_SUCCESS;
  503. Status = DfsGetDfsRootADObject( DCName,
  504. Root,
  505. &pRootObject );
  506. if (Status == ERROR_SUCCESS)
  507. {
  508. Status = DfsUpdateRemoteServerName( pRootObject,
  509. ServerName,
  510. RemainingName,
  511. Add );
  512. pRootObject->Release();
  513. }
  514. return Status;
  515. }
  516. #define UNICODE_STRING_STRUCT(s) \
  517. {sizeof(s) - sizeof(WCHAR), sizeof(s) - sizeof(WCHAR), (s)}
  518. static UNICODE_STRING DfsSpecialDCShares[] = {
  519. UNICODE_STRING_STRUCT(L"SYSVOL"),
  520. UNICODE_STRING_STRUCT(L"NETLOGON"),
  521. };
  522. //+-------------------------------------------------------------------------
  523. //
  524. // Function: DfsIsRemoteServerNameEqual
  525. //
  526. //
  527. // Returns: Status: Success or Error status code. pIsEqual = TRUE if
  528. // the remoteServerName contains the passed in pServerName in its entirety.
  529. //
  530. // Description: This routine reads the remote server name
  531. // attribute and does a string match on its components.
  532. //--------------------------------------------------------------------------
  533. DFSSTATUS
  534. DfsIsRemoteServerNameEqual(
  535. LPWSTR RootName,
  536. PUNICODE_STRING pServerName,
  537. PBOOLEAN pIsEqual)
  538. {
  539. HRESULT HResult = S_OK;
  540. DFSSTATUS Status = ERROR_SUCCESS;
  541. IADs *pObject = NULL;
  542. VARIANT Variant;
  543. LPWSTR pszAttrs[] = { RemoteServerNameString };
  544. DWORD Number = sizeof(pszAttrs) / sizeof(LPWSTR);
  545. DFS_TRACE_NORM( REFERRAL_SERVER, "Entering DfsIsRemoteServerNameEqual for RootName %ws, ServerName %wZ\n",
  546. RootName, pServerName);
  547. *pIsEqual = FALSE;
  548. Status = DfsGetDfsRootADObject(NULL,
  549. RootName,
  550. &pObject );
  551. if (Status == ERROR_SUCCESS)
  552. {
  553. VariantInit( &Variant );
  554. HResult = ADsBuildVarArrayStr( pszAttrs, Number, &Variant);
  555. if ( SUCCEEDED(HResult))
  556. {
  557. LONG StartNdx, LastNdx;
  558. SAFEARRAY *PropertyArray;
  559. BSTR RemoteServerNameBstr = SysAllocString(RemoteServerNameString);
  560. if (RemoteServerNameBstr == NULL)
  561. {
  562. Status = ERROR_NOT_ENOUGH_MEMORY;
  563. }
  564. if (Status == ERROR_SUCCESS)
  565. {
  566. HResult = pObject->GetEx( RemoteServerNameBstr, &Variant );
  567. if ( SUCCEEDED(HResult) )
  568. {
  569. PropertyArray = V_ARRAY( &Variant );
  570. HResult = SafeArrayGetLBound( PropertyArray, 1, &StartNdx );
  571. if ( SUCCEEDED(HResult) )
  572. {
  573. HResult = SafeArrayGetUBound( PropertyArray, 1, &LastNdx );
  574. }
  575. }
  576. else
  577. {
  578. DFS_TRACE_HIGH(REFERRAL_SERVER,
  579. "DfsIsRemoteServerNameEqual -GetEx failed for RootName %ws with Status %x\n",
  580. RootName, HResult);
  581. }
  582. if ( SUCCEEDED(HResult) &&
  583. (LastNdx > StartNdx) )
  584. {
  585. VARIANT VariantItem;
  586. for ( LONG Index = StartNdx; Index < LastNdx; Index++ )
  587. {
  588. VariantInit( &VariantItem );
  589. HResult = SafeArrayGetElement( PropertyArray,
  590. &Index,
  591. &VariantItem );
  592. if ( SUCCEEDED(HResult) )
  593. {
  594. UNICODE_STRING FirstComp, Replica;
  595. LPWSTR ReplicaString = V_BSTR( &VariantItem );
  596. Status = DfsRtlInitUnicodeStringEx( &Replica, ReplicaString );
  597. if(Status == ERROR_SUCCESS)
  598. {
  599. Status = DfsGetFirstComponent( &Replica, &FirstComp, NULL );
  600. if (Status == ERROR_SUCCESS)
  601. {
  602. //
  603. // See if this component matches our servername in its entirety.
  604. //
  605. if (RtlEqualDomainName( pServerName, &FirstComp ))
  606. {
  607. *pIsEqual = TRUE;
  608. }
  609. }
  610. }
  611. }
  612. else {
  613. Status = DfsGetErrorFromHr( HResult );
  614. DFS_TRACE_HIGH(REFERRAL_SERVER, "Leaving DfsGenerateReferralDataFromRemoteServerNames- SafeArrayGetElement for RootName %ws with Status %x\n",
  615. RootName, HResult);
  616. }
  617. VariantClear( &VariantItem );
  618. if (Status != ERROR_SUCCESS || *pIsEqual == TRUE)
  619. {
  620. break;
  621. }
  622. }
  623. }
  624. if (RemoteServerNameBstr != NULL)
  625. {
  626. SysFreeString( RemoteServerNameBstr );
  627. }
  628. }
  629. VariantClear( &Variant );
  630. }
  631. pObject->Release();
  632. }
  633. else
  634. {
  635. DFS_TRACE_HIGH(REFERRAL_SERVER, "DfsIsRemoteServerNameEqual- DfsGetDfsRootADObjectfailed for RootName %ws with Status %x\n",
  636. RootName, HResult);
  637. Status = DfsGetErrorFromHr( HResult );
  638. }
  639. DFS_TRACE_ERROR_HIGH( Status, REFERRAL_SERVER,
  640. "Leaving DfsIsRemoteServerNameEqual for RootName %ws, Server %wZ, Status %x, IsEqual? 0x%x\n",
  641. RootName, pServerName, HResult, *pIsEqual);
  642. return Status;
  643. }
  644. BOOLEAN
  645. DfsIsSpecialDomainShare(
  646. PUNICODE_STRING pShareName )
  647. {
  648. ULONG Index;
  649. ULONG TotalShares;
  650. BOOLEAN SpecialShare = FALSE;
  651. TotalShares = sizeof(DfsSpecialDCShares) / sizeof(DfsSpecialDCShares[0]);
  652. for (Index = 0; Index < TotalShares; Index++ )
  653. {
  654. if (DfsSpecialDCShares[Index].Length == pShareName->Length) {
  655. if (_wcsnicmp(DfsSpecialDCShares[Index].Buffer,
  656. pShareName->Buffer,
  657. pShareName->Length/sizeof(WCHAR)) == 0)
  658. {
  659. SpecialShare = TRUE;
  660. break;
  661. }
  662. }
  663. }
  664. return SpecialShare;
  665. }