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.

1104 lines
29 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 2000, Microsoft Corporation
  4. //
  5. // File: DfsAdsiApi.cxx
  6. //
  7. // Contents: Contains APIs to communicate with the DS
  8. //
  9. // Classes: none.
  10. //
  11. // History: March. 13 2001, Author: Rohanp
  12. //
  13. //-----------------------------------------------------------------------------
  14. #include "DfsAdsiAPi.hxx"
  15. #include "DfsError.hxx"
  16. #include "dfsgeneric.hxx"
  17. #include "dfsinit.hxx"
  18. #include "lm.h"
  19. #include "lmdfs.h"
  20. #include "strsafe.h"
  21. #include "dsgetdc.h"
  22. //
  23. // dfsdev: comment this properly.
  24. //
  25. LPWSTR RootDseString=L"LDAP://RootDSE";
  26. //
  27. // The prefix for AD path string. This is used to generate a path of
  28. // the form "LDAP://<dcname>/CN=,...DC=,..."
  29. //
  30. LPWSTR LdapPrefixString=L"LDAP://";
  31. DFSSTATUS
  32. DfsCreateDN(
  33. OUT LPWSTR PathString,
  34. IN size_t CharacterCount,
  35. LPWSTR DCName,
  36. LPWSTR PathPrefix,
  37. LPWSTR *CNNames );
  38. DFSSTATUS
  39. DfsGenerateRootCN(
  40. LPWSTR RootName,
  41. LPWSTR *pRootCNName);
  42. VOID
  43. DfsDeleteRootCN(
  44. LPWSTR PathString);
  45. DFSSTATUS
  46. DfsGenerateADPathString(
  47. IN LPWSTR DCName,
  48. IN LPWSTR ObjectName,
  49. IN LPWSTR PathPrefix,
  50. OUT LPOLESTR *pPathString);
  51. VOID
  52. DfsDeleteADPathString(
  53. LPWSTR PathString);
  54. DFSSTATUS
  55. DfsGetADObjectWithDsGetDCName(
  56. LPWSTR DCName,
  57. REFIID Id,
  58. LPWSTR ObjectName,
  59. ULONG GetDCFlags,
  60. PVOID *ppObject );
  61. //+-------------------------------------------------------------------------
  62. //
  63. // Function: DfsCreateDN
  64. //
  65. // Arguments:
  66. // OUT LPWSTR PathString -> updated pathstring on return
  67. // IN size_t CharacterCount -> number of characters in PathString
  68. // LPWSTR DCName -> DcNAME to use
  69. // LPWSTR PathPrefix -> path prefix if any
  70. // LPWSTR *CNNames -> Array of CNNames.
  71. // Returns: Status
  72. // ERROR_SUCCESS on success
  73. // ERROR status code otherwise
  74. //
  75. //
  76. // Description: dfscreatedn take a pathstring and fills it with the
  77. // information necessary for the path to be used as a
  78. // Distinguished Name.
  79. // It starts the string with LDAP://, follows that with
  80. // a DCName if supplied, and then adds the array of
  81. // CNNames passed in one after the other , each one
  82. // followed by a , the final outcome is something like:
  83. // LDAP://ntdev-dc-01/CN=Dfs-Configuration, CN=System, Dc=Ntdev, etc
  84. //
  85. //--------------------------------------------------------------------------
  86. DFSSTATUS
  87. DfsCreateDN(
  88. OUT LPWSTR PathString,
  89. IN size_t CharacterCount,
  90. LPWSTR DCName,
  91. LPWSTR PathPrefix,
  92. LPWSTR *CNNames )
  93. {
  94. LPWSTR *InArray = CNNames;
  95. LPWSTR CNName;
  96. HRESULT HResult = S_OK;
  97. size_t CurrentCharacterCount = CharacterCount;
  98. DFSSTATUS Status = ERROR_SUCCESS;
  99. //
  100. // If we are not adding the usual "LDAP://" string,
  101. // Start with a NULL so string cat will work right.
  102. //
  103. if (CurrentCharacterCount <=0 )
  104. {
  105. return ERROR_INVALID_PARAMETER;
  106. }
  107. if (PathPrefix != NULL)
  108. {
  109. HResult = StringCchCopy( PathString,
  110. CurrentCharacterCount,
  111. PathPrefix );
  112. } else {
  113. *PathString = UNICODE_NULL;
  114. }
  115. if (SUCCEEDED(HResult)) {
  116. //
  117. // if the dc name is specified, we want to go to a specific dc
  118. // add that in.
  119. //
  120. if (!IsEmptyString(DCName))
  121. {
  122. HResult = StringCchCat( PathString,
  123. CurrentCharacterCount,
  124. DCName );
  125. if (SUCCEEDED(HResult))
  126. {
  127. HResult = StringCchCat( PathString,
  128. CurrentCharacterCount,
  129. L"/" );
  130. }
  131. }
  132. }
  133. //
  134. // Now treat the CNNames as an array of LPWSTR and add each one of
  135. // the lpwstr to our path.
  136. //
  137. if (SUCCEEDED(HResult)) {
  138. if (CNNames != NULL)
  139. {
  140. while (((CNName = *InArray++) != NULL) &&
  141. (SUCCEEDED(HResult)))
  142. {
  143. HResult = StringCchCat( PathString,
  144. CurrentCharacterCount,
  145. CNName );
  146. if ((*InArray != NULL) &&
  147. (SUCCEEDED(HResult)))
  148. {
  149. HResult = StringCchCat( PathString,
  150. CurrentCharacterCount,
  151. L"," );
  152. }
  153. }
  154. }
  155. }
  156. if (!SUCCEEDED(HResult))
  157. {
  158. Status = HRESULT_CODE(HResult);
  159. }
  160. return Status;
  161. }
  162. DFSSTATUS
  163. DfsGenerateDfsAdNameContext(
  164. PUNICODE_STRING pString )
  165. {
  166. IADs *pRootDseObject;
  167. HRESULT HResult;
  168. VARIANT VarDSRoot;
  169. DFSSTATUS Status = ERROR_SUCCESS;
  170. BSTR NamingContext;
  171. NamingContext = SysAllocString(L"defaultNamingContext");
  172. if (NamingContext == NULL)
  173. {
  174. return ERROR_NOT_ENOUGH_MEMORY;
  175. }
  176. HResult = ADsGetObject( RootDseString,
  177. IID_IADs,
  178. (void **)&pRootDseObject );
  179. if (SUCCEEDED(HResult))
  180. {
  181. VariantInit( &VarDSRoot );
  182. // Get the Directory Object on the root DSE, to get to the server configuration
  183. HResult = pRootDseObject->Get(NamingContext, &VarDSRoot);
  184. if (SUCCEEDED(HResult))
  185. {
  186. Status = DfsCreateUnicodeStringFromString( pString,
  187. (LPWSTR)V_BSTR(&VarDSRoot) );
  188. }
  189. VariantClear(&VarDSRoot);
  190. pRootDseObject->Release();
  191. }
  192. if (!SUCCEEDED(HResult))
  193. {
  194. Status = DfsGetErrorFromHr(HResult);
  195. }
  196. SysFreeString(NamingContext);
  197. return Status;
  198. }
  199. DFSSTATUS
  200. DfsGenerateDfsAdNameContextForDomain(
  201. PUNICODE_STRING pString,
  202. LPWSTR DCName )
  203. {
  204. IADs *pRootDseObject;
  205. HRESULT HResult;
  206. VARIANT VarDSRoot;
  207. DFSSTATUS Status = ERROR_SUCCESS;
  208. BSTR NamingContext;
  209. LPWSTR CNNames[2];
  210. LPWSTR PathString = NULL;
  211. CNNames[0] = L"RootDSE";
  212. CNNames[1] = NULL;
  213. size_t CharacterCount = 1;
  214. CharacterCount += wcslen(LdapPrefixString);
  215. if (DCName)
  216. {
  217. CharacterCount += wcslen(DCName) + 1;
  218. CharacterCount++;
  219. }
  220. CharacterCount += wcslen(CNNames[0]) + 1;
  221. CharacterCount++;
  222. PathString = new WCHAR[CharacterCount];
  223. if (PathString == NULL)
  224. {
  225. return ERROR_NOT_ENOUGH_MEMORY;
  226. }
  227. Status = DfsCreateDN( PathString,
  228. CharacterCount,
  229. DCName,
  230. LdapPrefixString,
  231. CNNames);
  232. if (Status == ERROR_SUCCESS)
  233. {
  234. NamingContext = SysAllocString(L"defaultNamingContext");
  235. if (NamingContext == NULL)
  236. {
  237. Status = ERROR_NOT_ENOUGH_MEMORY;
  238. }
  239. if (Status == ERROR_SUCCESS)
  240. {
  241. HResult = ADsGetObject( PathString,
  242. IID_IADs,
  243. (void **)&pRootDseObject );
  244. if (SUCCEEDED(HResult))
  245. {
  246. VariantInit( &VarDSRoot );
  247. // Get the Directory Object on the root DSE, to get to the server configuration
  248. HResult = pRootDseObject->Get(NamingContext, &VarDSRoot);
  249. if (SUCCEEDED(HResult))
  250. {
  251. Status = DfsCreateUnicodeStringFromString( pString,
  252. (LPWSTR)V_BSTR(&VarDSRoot) );
  253. }
  254. VariantClear(&VarDSRoot);
  255. pRootDseObject->Release();
  256. }
  257. if (!SUCCEEDED(HResult))
  258. {
  259. Status = DfsGetErrorFromHr(HResult);
  260. }
  261. SysFreeString(NamingContext);
  262. }
  263. delete [] PathString;
  264. }
  265. return Status;
  266. }
  267. #define MAX_CN_ARRAY 5
  268. DFSSTATUS
  269. DfsGenerateADPathString(
  270. IN LPWSTR DCName,
  271. IN LPWSTR ObjectName,
  272. IN LPWSTR PathPrefix,
  273. OUT LPWSTR *pPathString)
  274. {
  275. LPWSTR CNNames[MAX_CN_ARRAY];
  276. ULONG Index;
  277. LPWSTR ADNameContext;
  278. size_t CharacterCount = 0;
  279. size_t UseCount;
  280. HRESULT HResult = S_OK;
  281. DFSSTATUS Status = ERROR_SUCCESS;
  282. do {
  283. CharacterCount = 1; // For null termination;
  284. if (PathPrefix != NULL)
  285. {
  286. Status = DfsStringCchLength( PathPrefix,
  287. MAXUSHORT,
  288. &UseCount);
  289. if (Status != ERROR_SUCCESS)
  290. break;
  291. CharacterCount += UseCount + 1; // path prefix + seperator
  292. }
  293. //
  294. // ADNameContext will be of the form CN=NtDev, CN=Micorosft etc etc.
  295. //
  296. ADNameContext = DfsGetDfsAdNameContextString();
  297. if (ADNameContext == NULL)
  298. {
  299. Status = ERROR_NOT_READY;
  300. break;
  301. }
  302. if (DCName != NULL)
  303. {
  304. Status = DfsStringCchLength( DCName,
  305. MAXUSHORT,
  306. &UseCount);
  307. if (Status != ERROR_SUCCESS)
  308. break;
  309. CharacterCount += UseCount + 1; //dcname + seperator;
  310. }
  311. if (ObjectName != NULL)
  312. {
  313. Status = DfsStringCchLength( ObjectName,
  314. MAXUSHORT,
  315. &UseCount);
  316. if (Status != ERROR_SUCCESS)
  317. break;
  318. CharacterCount += UseCount + 1; //ObjectName + seperator
  319. }
  320. Status = DfsStringCchLength( DFS_AD_CONFIG_DATA,
  321. MAXUSHORT,
  322. &UseCount);
  323. if (Status != ERROR_SUCCESS)
  324. break;
  325. CharacterCount += UseCount + 1; // config container + seperator;
  326. Status = DfsStringCchLength( ADNameContext,
  327. MAXUSHORT,
  328. &UseCount);
  329. if (Status != ERROR_SUCCESS)
  330. break;
  331. CharacterCount += UseCount + 1; //context + seperator;
  332. //
  333. // Note: Be very wary here. We have a fixed CNNames array, and
  334. // we are using that knowledge here. Adding any more CNNames
  335. // needs to bump up the array count.
  336. //
  337. Index = 0;
  338. if (ObjectName != NULL)
  339. {
  340. CNNames[Index++] = ObjectName;
  341. }
  342. CNNames[Index++] = DFS_AD_CONFIG_DATA;
  343. CNNames[Index++] = ADNameContext;
  344. CNNames[Index] = NULL;
  345. *pPathString = new WCHAR[CharacterCount];
  346. if (*pPathString == NULL)
  347. {
  348. Status = ERROR_NOT_ENOUGH_MEMORY;
  349. break;
  350. }
  351. Status = DfsCreateDN( *pPathString,
  352. CharacterCount,
  353. DCName,
  354. PathPrefix,
  355. CNNames);
  356. if (Status != ERROR_SUCCESS)
  357. {
  358. delete [] *pPathString;
  359. *pPathString = NULL;
  360. break;
  361. }
  362. } while (FALSE);
  363. return Status;
  364. }
  365. VOID
  366. DfsDeleteADPathString(
  367. LPWSTR PathString)
  368. {
  369. delete [] PathString;
  370. return NOTHING;
  371. }
  372. DFSSTATUS
  373. DfsGetADObjectWithDsGetDCName(
  374. LPWSTR DCName,
  375. REFIID Id,
  376. LPWSTR ObjectName,
  377. ULONG GetDCFlags,
  378. PVOID *ppObject )
  379. //
  380. // This function calls ADSI to open the object. Alas, we're not thrilled with
  381. // how ADSI does DC-stickyness so we'll work around that by getting the DC
  382. // name and passing it in to ADSI ourselves so that they don't have to bother.
  383. //
  384. {
  385. HRESULT HResult;
  386. LPWSTR PathString;
  387. DFSSTATUS Status;
  388. LPWSTR DCNameToUse = DCName; // may be DCName or pointer into dcInfo
  389. DOMAIN_CONTROLLER_INFO *dcInfo = NULL; // be sure to free if not null
  390. if (DCName == NULL) {
  391. Status = DsGetDcName( NULL, // computer name
  392. NULL, // domain name
  393. NULL, // domain guid
  394. NULL, // site name
  395. GetDCFlags,
  396. &dcInfo
  397. );
  398. if ((Status == ERROR_SUCCESS) && (dcInfo->DomainControllerName != NULL)) {
  399. DCNameToUse = dcInfo->DomainControllerName;
  400. // don't include the double slashes at the front of the DC name
  401. while (*DCNameToUse == L'\\') {
  402. DCNameToUse++;
  403. }
  404. }
  405. }
  406. Status = DfsGenerateADPathString( DCNameToUse,
  407. ObjectName,
  408. LdapPrefixString,
  409. &PathString );
  410. if (dcInfo != NULL) {
  411. (VOID) NetApiBufferFree( dcInfo ); // ignore status returned
  412. }
  413. if (Status != ERROR_SUCCESS)
  414. {
  415. return Status;
  416. }
  417. //
  418. // open dfs configuration container for enumeration.
  419. //
  420. HResult = ADsOpenObject(PathString,
  421. NULL,
  422. NULL,
  423. ADS_SECURE_AUTHENTICATION | ADS_FAST_BIND | ADS_SERVER_BIND,
  424. Id,
  425. ppObject );
  426. Status = DfsGetErrorFromHr(HResult);
  427. DfsDeleteADPathString( PathString );
  428. return Status;
  429. }
  430. DFSSTATUS
  431. DfsGetADObject(
  432. LPWSTR DCName,
  433. REFIID Id,
  434. LPWSTR ObjectName,
  435. PVOID *ppObject )
  436. {
  437. DFSSTATUS Status;
  438. Status = DfsGetADObjectWithDsGetDCName( DCName,
  439. Id,
  440. ObjectName,
  441. DS_DIRECTORY_SERVICE_REQUIRED,
  442. ppObject );
  443. if (Status != ERROR_SUCCESS && DCName == NULL) {
  444. Status = DfsGetADObjectWithDsGetDCName( DCName,
  445. Id,
  446. ObjectName,
  447. DS_FORCE_REDISCOVERY | DS_DIRECTORY_SERVICE_REQUIRED,
  448. ppObject );
  449. }
  450. return Status;
  451. }
  452. //
  453. // Given the root share name, get the root object.
  454. //
  455. DFSSTATUS
  456. DfsGetDfsRootADObject(
  457. LPWSTR DCName,
  458. LPWSTR RootName,
  459. IADs **ppRootObject )
  460. {
  461. LPWSTR RootCNName = NULL;
  462. DFSSTATUS Status = ERROR_SUCCESS;
  463. Status = DfsGenerateRootCN( RootName, &RootCNName );
  464. if (Status == ERROR_SUCCESS)
  465. {
  466. Status = DfsGetADObject( DCName,
  467. IID_IADs,
  468. RootCNName,
  469. (PVOID *)ppRootObject );
  470. DfsDeleteRootCN( RootCNName );
  471. }
  472. return Status;
  473. }
  474. DFSSTATUS
  475. PackRootName(
  476. LPWSTR Name,
  477. PDFS_INFO_200 pDfsInfo200,
  478. PULONG pBufferSize,
  479. PULONG pTotalSize )
  480. {
  481. size_t CharacterCount, ByteCount;
  482. ULONG NeedSize;
  483. DFSSTATUS Status = ERROR_SUCCESS;
  484. HRESULT HResult;
  485. LPWSTR UseName;
  486. UseName = &Name[3]; // skip over the leading whacks.
  487. HResult = StringCchLength( UseName,
  488. MAXUSHORT,
  489. &CharacterCount );
  490. if (SUCCEEDED(HResult))
  491. {
  492. CharacterCount += 1; // For null termination;
  493. ByteCount = CharacterCount * sizeof(WCHAR);
  494. NeedSize = sizeof(DFS_INFO_200) + ByteCount;
  495. *pTotalSize += NeedSize;
  496. if (*pBufferSize >= NeedSize)
  497. {
  498. LPWSTR pStringBuffer;
  499. pStringBuffer = (LPWSTR)((ULONG_PTR)(pDfsInfo200) + *pBufferSize - ByteCount);
  500. HResult = StringCchCopy( pStringBuffer,
  501. CharacterCount,
  502. UseName );
  503. if (SUCCEEDED(HResult))
  504. {
  505. pDfsInfo200->FtDfsName = (LPWSTR)pStringBuffer;
  506. *pBufferSize -= NeedSize;
  507. }
  508. }
  509. else
  510. {
  511. Status = ERROR_BUFFER_OVERFLOW;
  512. *pBufferSize = 0;
  513. }
  514. }
  515. if (!SUCCEEDED(HResult))
  516. {
  517. Status = HRESULT_CODE(HResult);
  518. }
  519. return Status;
  520. }
  521. DFSSTATUS
  522. DfsGetDfsConfigurationObject(
  523. LPWSTR DCName,
  524. IADsContainer **ppDfsConfiguration )
  525. {
  526. DFSSTATUS Status;
  527. Status = DfsGetADObject( DCName,
  528. IID_IADsContainer,
  529. NULL,
  530. (PVOID *)ppDfsConfiguration );
  531. return Status;
  532. }
  533. DFSSTATUS
  534. DfsGetBinaryFromVariant(VARIANT *ovData, BYTE ** ppBuf,
  535. unsigned long * pcBufLen)
  536. {
  537. DFSSTATUS Status = ERROR_INVALID_PARAMETER;
  538. void * pArrayData = NULL;
  539. //Binary data is stored in the variant as an array of unsigned char
  540. if(ovData->vt == (VT_ARRAY|VT_UI1))
  541. {
  542. //Retrieve size of array
  543. *pcBufLen = ovData->parray->rgsabound[0].cElements;
  544. *ppBuf = new BYTE[*pcBufLen]; //Allocate a buffer to store the data
  545. if(*ppBuf != NULL)
  546. {
  547. //Obtain safe pointer to the array
  548. SafeArrayAccessData(ovData->parray,&pArrayData);
  549. //Copy the bitmap into our buffer
  550. memcpy(*ppBuf, pArrayData, *pcBufLen);
  551. //Unlock the variant data
  552. SafeArrayUnaccessData(ovData->parray);
  553. Status = ERROR_SUCCESS;
  554. }
  555. else
  556. {
  557. Status = ERROR_NOT_ENOUGH_MEMORY;
  558. }
  559. }
  560. return Status;
  561. }
  562. DFSSTATUS
  563. DfsCheckRootADObjectExistence(
  564. LPWSTR DCName,
  565. PUNICODE_STRING pRootName,
  566. GUID *pGuid )
  567. {
  568. DFSSTATUS Status = ERROR_SUCCESS;
  569. IADs *pRootObject = NULL;
  570. BYTE *pBuffer = NULL;
  571. ULONG Length = 0;
  572. UNICODE_STRING RootName;
  573. Status = DfsCreateUnicodeString( &RootName,
  574. pRootName );
  575. if (Status == ERROR_SUCCESS)
  576. {
  577. Status = DfsGetDfsRootADObject( DCName,
  578. RootName.Buffer,
  579. &pRootObject );
  580. if (Status == ERROR_SUCCESS)
  581. {
  582. //
  583. //
  584. // Now check for ability to read an attribute...
  585. VARIANT Variant;
  586. HRESULT HResult;
  587. VariantInit(&Variant);
  588. LPWSTR pszAttrs[] = { L"pKTGuid" };
  589. DWORD dwNumber = sizeof( pszAttrs ) /sizeof(LPWSTR);
  590. HResult = ADsBuildVarArrayStr( pszAttrs, dwNumber, &Variant );
  591. if (HResult == S_OK)
  592. {
  593. HResult = pRootObject->GetInfoEx(Variant, 0);
  594. if (HResult != S_OK)
  595. {
  596. Status = DfsGetErrorFromHr(HResult);
  597. }
  598. }
  599. VariantClear(&Variant);
  600. VariantInit( &Variant );
  601. if ((Status == ERROR_SUCCESS) && pGuid)
  602. {
  603. //
  604. // Make a BSTR out of WCHAR *
  605. //
  606. BSTR PktGuidBstr = SysAllocString(L"pKTGuid");
  607. if (PktGuidBstr == NULL)
  608. {
  609. Status = ERROR_NOT_ENOUGH_MEMORY;
  610. }
  611. if (Status == ERROR_SUCCESS)
  612. {
  613. HResult = pRootObject->Get( PktGuidBstr, &Variant );
  614. if (HResult == S_OK)
  615. {
  616. Status = DfsGetBinaryFromVariant( &Variant, &pBuffer, &Length );
  617. if (Status == ERROR_SUCCESS)
  618. {
  619. if (Length > sizeof(GUID))
  620. {
  621. Length = sizeof(GUID);
  622. }
  623. RtlCopyMemory( pGuid, pBuffer, Length);
  624. delete [] pBuffer;
  625. }
  626. }
  627. else
  628. {
  629. if (HResult != S_OK)
  630. {
  631. Status = DfsGetErrorFromHr(HResult);
  632. }
  633. }
  634. if (PktGuidBstr != NULL) // paranoia
  635. {
  636. SysFreeString( PktGuidBstr );
  637. }
  638. }
  639. }
  640. pRootObject->Release();
  641. }
  642. DfsFreeUnicodeString( &RootName );
  643. }
  644. return Status;
  645. }
  646. DFSSTATUS
  647. DfsDeleteDfsRootObject(
  648. LPWSTR DCName,
  649. LPWSTR RootName )
  650. {
  651. BSTR ObjectName, ObjectClass;
  652. DFSSTATUS Status;
  653. HRESULT HResult;
  654. IADsContainer *pDfsConfiguration;
  655. IADs *pRootObject;
  656. Status = DfsGetDfsRootADObject( DCName,
  657. RootName,
  658. &pRootObject );
  659. if (Status == ERROR_SUCCESS)
  660. {
  661. Status = DfsGetDfsConfigurationObject( DCName,
  662. &pDfsConfiguration );
  663. if (Status == ERROR_SUCCESS)
  664. {
  665. HResult = pRootObject->get_Name(&ObjectName);
  666. if (SUCCEEDED(HResult))
  667. {
  668. HResult = pRootObject->get_Class(&ObjectClass);
  669. if (SUCCEEDED(HResult))
  670. {
  671. HResult = pDfsConfiguration->Delete( ObjectClass,
  672. ObjectName );
  673. SysFreeString(ObjectClass);
  674. }
  675. SysFreeString(ObjectName);
  676. }
  677. pDfsConfiguration->Release();
  678. Status = DfsGetErrorFromHr(HResult);
  679. }
  680. pRootObject->Release();
  681. }
  682. return Status;
  683. }
  684. DFSSTATUS
  685. DfsEnumerateDfsADRoots(
  686. LPWSTR DCName,
  687. PULONG_PTR pBuffer,
  688. PULONG pBufferSize,
  689. PULONG pEntriesRead,
  690. DWORD MaxEntriesToRead,
  691. LPDWORD pResumeHandle,
  692. PULONG pSizeRequired )
  693. {
  694. HRESULT HResult;
  695. IADsContainer *pDfsConfiguration;
  696. IEnumVARIANT *pEnum;
  697. ULONG TotalSize = 0;
  698. ULONG TotalEntries = 0;
  699. PDFS_INFO_200 pDfsInfo200;
  700. ULONG BufferSize = *pBufferSize;
  701. DFSSTATUS Status;
  702. LONG ResumeCount;
  703. LONG NumRoots;
  704. //
  705. // point the dfsinfo200 structure to the start of buffer passed in
  706. // we will use this as an array of info200 buffers.
  707. //
  708. pDfsInfo200 = (PDFS_INFO_200)*pBuffer;
  709. Status = DfsGetDfsConfigurationObject( DCName,
  710. &pDfsConfiguration );
  711. if (Status == ERROR_SUCCESS)
  712. {
  713. HResult = ADsBuildEnumerator( pDfsConfiguration,
  714. &pEnum );
  715. if (SUCCEEDED(HResult))
  716. {
  717. VARIANT Variant;
  718. ULONG Fetched;
  719. BSTR BString;
  720. IADs *pRootObject;
  721. IDispatch *pDisp;
  722. ResumeCount = 0;
  723. NumRoots = 0;
  724. // See if we need to resume from a previous enumeration.
  725. if (pResumeHandle && *pResumeHandle > 0)
  726. {
  727. ResumeCount = *pResumeHandle;
  728. }
  729. VariantInit(&Variant);
  730. while ((HResult = ADsEnumerateNext(pEnum,
  731. 1,
  732. &Variant,
  733. &Fetched)) == S_OK)
  734. {
  735. if (TotalEntries >= MaxEntriesToRead)
  736. {
  737. break;
  738. }
  739. // Skip ResumeCount number of entries
  740. NumRoots++;
  741. if (NumRoots <= ResumeCount)
  742. {
  743. continue;
  744. }
  745. pDisp = V_DISPATCH(&Variant);
  746. pDisp->QueryInterface(IID_IADs, (void **)&pRootObject);
  747. pDisp->Release();
  748. HResult = pRootObject->get_Name(&BString);
  749. if (HResult == S_OK)
  750. {
  751. Status = PackRootName( BString, pDfsInfo200, &BufferSize, &TotalSize );
  752. if (Status == ERROR_SUCCESS)
  753. {
  754. TotalEntries++;
  755. pDfsInfo200++;
  756. }
  757. SysFreeString(BString);
  758. }
  759. pRootObject->Release();
  760. // DfsDev: investigate. this causes an av.
  761. // VariantClear(&Variant);
  762. }
  763. if (HResult == S_FALSE)
  764. {
  765. HResult = S_OK;
  766. }
  767. ADsFreeEnumerator( pEnum );
  768. }
  769. pDfsConfiguration->Release();
  770. if (!SUCCEEDED(HResult))
  771. {
  772. Status = DfsGetErrorFromHr(HResult);
  773. }
  774. }
  775. if ((Status == ERROR_SUCCESS) || (Status == ERROR_BUFFER_OVERFLOW))
  776. {
  777. *pSizeRequired = TotalSize;
  778. if (TotalSize > *pBufferSize)
  779. {
  780. Status = ERROR_BUFFER_OVERFLOW;
  781. }
  782. else if (TotalEntries == 0)
  783. {
  784. Status = ERROR_NO_MORE_ITEMS;
  785. }
  786. }
  787. if (Status == ERROR_SUCCESS)
  788. {
  789. *pEntriesRead = TotalEntries;
  790. if (pResumeHandle)
  791. {
  792. *pResumeHandle = NumRoots;
  793. }
  794. }
  795. return Status;
  796. }
  797. DFSSTATUS
  798. DfsGenerateRootCN(
  799. LPWSTR RootName,
  800. LPWSTR *pRootCNName)
  801. {
  802. size_t CharacterCount, UseCount;
  803. LPWSTR UsePrefix = L"CN=";
  804. HRESULT HResult;
  805. DFSSTATUS Status = ERROR_SUCCESS;
  806. LPWSTR RootCNName;
  807. CharacterCount = 1; // for null termination;
  808. HResult = StringCchLength( UsePrefix,
  809. MAXUSHORT,
  810. &UseCount);
  811. if (SUCCEEDED(HResult))
  812. {
  813. CharacterCount += UseCount;
  814. HResult = StringCchLength( RootName,
  815. MAXUSHORT,
  816. &UseCount);
  817. if (SUCCEEDED(HResult))
  818. {
  819. CharacterCount += UseCount;
  820. }
  821. }
  822. if (SUCCEEDED(HResult))
  823. {
  824. RootCNName = new WCHAR[CharacterCount];
  825. if (RootCNName == NULL)
  826. {
  827. Status = ERROR_NOT_ENOUGH_MEMORY;
  828. }
  829. if (Status == ERROR_SUCCESS)
  830. {
  831. HResult = StringCchCopy( RootCNName,
  832. CharacterCount,
  833. UsePrefix );
  834. if (SUCCEEDED(HResult))
  835. {
  836. HResult = StringCchCat( RootCNName,
  837. CharacterCount,
  838. RootName );
  839. }
  840. if (!SUCCEEDED(HResult))
  841. {
  842. delete [] RootCNName;
  843. }
  844. }
  845. }
  846. //
  847. // Note: here are 2 possibilities. We either have a HResult that is
  848. // not S_OK or we have a Status that is already set.
  849. // If the HResult is not S_OK, convert that to a status and return
  850. // Otherwise, use the status as set by the above code.
  851. // IF YOU DO HRESULT_CODE() at this point on a S_OK Hresult, we will
  852. // lost the status above.
  853. //
  854. if (!SUCCEEDED(HResult))
  855. {
  856. Status = HRESULT_CODE(HResult);
  857. }
  858. if (Status == ERROR_SUCCESS)
  859. {
  860. *pRootCNName = RootCNName;
  861. }
  862. return Status;
  863. }
  864. VOID
  865. DfsDeleteRootCN(
  866. LPWSTR RootCNName)
  867. {
  868. delete [] RootCNName;
  869. return NOTHING;
  870. }
  871. //
  872. // Given a DFS rootname, this spews out a heap-allocated, NULL terminated
  873. // string containing the LDAP name context. This string, for example
  874. // ends up in the FTDfsObjectDN value name in the registry.
  875. // eg: CN=Rootname,CN=Dfs-Configuration,CN=System,DC=supwdomain,DC=nttest, ...
  876. //
  877. DFSSTATUS
  878. DfsGenerateDNPathString(
  879. LPWSTR RootObjName,
  880. OUT LPWSTR *pPathString)
  881. {
  882. DFSSTATUS Status;
  883. LPWSTR RootCNName;
  884. //
  885. // Generate the CN=Rootname part.
  886. //
  887. Status = DfsGenerateRootCN( RootObjName, &RootCNName );
  888. if (Status == ERROR_SUCCESS)
  889. {
  890. //
  891. // Now add in the rest of the CN and DC configuration strings.
  892. //
  893. Status = DfsGenerateADPathString( NULL,
  894. RootCNName,
  895. NULL,
  896. pPathString );
  897. DfsDeleteRootCN( RootCNName );
  898. }
  899. return Status;
  900. }
  901. VOID
  902. DfsDeleteDNPathString(
  903. LPWSTR PathString)
  904. {
  905. DfsDeleteADPathString( PathString );
  906. return NOTHING;
  907. }