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.

999 lines
26 KiB

  1. #include <Windows.h>
  2. #include <LM.h>
  3. #include <DsRole.h>
  4. #include <Ntdsapi.h>
  5. #include "Common.hpp"
  6. #include "EaLen.hpp"
  7. #include "AdsiHelpers.h"
  8. #include "GetDcName.h"
  9. namespace
  10. {
  11. //-----------------------------------------------------------------------------
  12. // CApi Class
  13. //
  14. // This template class wraps the logic for loading a library and retrieving
  15. // a procedure address. It manages loading and unloading of the library.
  16. //-----------------------------------------------------------------------------
  17. template<class T>
  18. class CApi
  19. {
  20. public:
  21. CApi(PCWSTR pszLibrary, PCSTR pszProcedure) :
  22. m_dwError(ERROR_SUCCESS),
  23. m_pApi(NULL)
  24. {
  25. m_hLibrary = LoadLibrary(pszLibrary);
  26. if (m_hLibrary)
  27. {
  28. m_pApi = (T) GetProcAddress(m_hLibrary, pszProcedure);
  29. if (m_pApi == NULL)
  30. {
  31. m_dwError = ::GetLastError();
  32. }
  33. }
  34. else
  35. {
  36. m_dwError = ::GetLastError();
  37. }
  38. }
  39. ~CApi()
  40. {
  41. if (m_hLibrary)
  42. {
  43. FreeLibrary(m_hLibrary);
  44. }
  45. }
  46. operator T()
  47. {
  48. return m_pApi;
  49. }
  50. DWORD GetLastError() const
  51. {
  52. return m_dwError;
  53. }
  54. protected:
  55. DWORD m_dwError;
  56. HMODULE m_hLibrary;
  57. T m_pApi;
  58. };
  59. }
  60. //
  61. // Declare pointer to DsGetDcName API.
  62. //
  63. typedef DSGETDCAPI DWORD (WINAPI* PDSGETDCNAME)(
  64. IN LPCWSTR ComputerName OPTIONAL,
  65. IN LPCWSTR DomainName OPTIONAL,
  66. IN GUID *DomainGuid OPTIONAL,
  67. IN LPCWSTR SiteName OPTIONAL,
  68. IN ULONG Flags,
  69. OUT PDOMAIN_CONTROLLER_INFOW *DomainControllerInfo
  70. );
  71. typedef DWORD (WINAPI* PDSROLEGETPRIMARYDOMAININFORMATION)(
  72. IN LPCWSTR lpServer OPTIONAL,
  73. IN DSROLE_PRIMARY_DOMAIN_INFO_LEVEL InfoLevel,
  74. OUT PBYTE *Buffer
  75. );
  76. typedef VOID (WINAPI* PDSROLEFREEMEMORY)(
  77. IN PVOID Buffer
  78. );
  79. typedef NTDSAPI DWORD (WINAPI* PDSBIND)(LPCWSTR, LPCWSTR, HANDLE*);
  80. typedef NTDSAPI DWORD (WINAPI* PDSUNBIND)(HANDLE*);
  81. typedef NTDSAPI DWORD (WINAPI* PDSLISTROLES)(HANDLE, PDS_NAME_RESULTW*);
  82. typedef NTDSAPI void (WINAPI* PDSFREENAMERESULT)(DS_NAME_RESULTW*);
  83. typedef HRESULT (WINAPI* PADSGETOBJECT)(LPCWSTR, REFIID, VOID**);
  84. //-----------------------------------------------------------------------------
  85. // GetDcName4 Function
  86. //
  87. // Synopsis
  88. // Retrieves the DNS and flat (NetBIOS) names of a domain controller in the
  89. // specified domain.
  90. //
  91. // Note that this function is for use in code that may be loaded on NT4 or
  92. // earlier machines. If code is only loaded on W2K or later machines then use
  93. // GetDcName5 function instead.
  94. //
  95. // Arguments
  96. // IN pszDomainName - the DNS or NetBIOS name of the domain or null which means
  97. // the domain that this machine belongs to
  98. // IN ulFlags - DsGetDcName option flags
  99. // OUT strNameDns - if available, the DNS name of a domain controller
  100. // OUT strNameFlat - if available, the flat name of a domain controller
  101. //
  102. // Return Value
  103. // A Win32 error code.
  104. //-----------------------------------------------------------------------------
  105. DWORD __stdcall GetDcName4(PCWSTR pszDomainName, ULONG ulFlags, _bstr_t& strNameDns, _bstr_t& strNameFlat)
  106. {
  107. DWORD dwError = ERROR_SUCCESS;
  108. //
  109. // Must load procedure address explicitly as this function
  110. // must be loadable in code that may be running on NT4 machines.
  111. //
  112. PDSGETDCNAME pDsGetDcName = NULL;
  113. HMODULE hNetApi32 = LoadLibrary(L"NetApi32.dll");
  114. if (hNetApi32)
  115. {
  116. pDsGetDcName = (PDSGETDCNAME)GetProcAddress(hNetApi32, "DsGetDcNameW");
  117. }
  118. //
  119. // If address of DsGetDcName function obtained then use
  120. // this API otherwise use NetGetDCName function.
  121. //
  122. if (pDsGetDcName)
  123. {
  124. ULONG ul = ulFlags & ~(DS_RETURN_DNS_NAME|DS_RETURN_FLAT_NAME);
  125. PDOMAIN_CONTROLLER_INFO pdciInfo = NULL;
  126. dwError = pDsGetDcName(NULL, pszDomainName, NULL, NULL, ul, &pdciInfo);
  127. if (dwError == ERROR_SUCCESS)
  128. {
  129. if (pdciInfo->Flags & DS_DS_FLAG)
  130. {
  131. if (pdciInfo->Flags & DS_DNS_CONTROLLER_FLAG)
  132. {
  133. strNameDns = pdciInfo->DomainControllerName;
  134. NetApiBufferFree(pdciInfo);
  135. pdciInfo = NULL;
  136. dwError = pDsGetDcName(NULL, pszDomainName, NULL, NULL, ul | DS_RETURN_FLAT_NAME, &pdciInfo);
  137. if (dwError == ERROR_SUCCESS)
  138. {
  139. strNameFlat = pdciInfo->DomainControllerName;
  140. }
  141. }
  142. else
  143. {
  144. strNameFlat = pdciInfo->DomainControllerName;
  145. NetApiBufferFree(pdciInfo);
  146. pdciInfo = NULL;
  147. dwError = pDsGetDcName(NULL, pszDomainName, NULL, NULL, ul | DS_RETURN_DNS_NAME, &pdciInfo);
  148. if (dwError == ERROR_SUCCESS)
  149. {
  150. strNameDns = pdciInfo->DomainControllerName;
  151. }
  152. }
  153. }
  154. else
  155. {
  156. strNameDns = (LPCTSTR)NULL;
  157. strNameFlat = pdciInfo->DomainControllerName;
  158. }
  159. }
  160. if (pdciInfo)
  161. {
  162. NetApiBufferFree(pdciInfo);
  163. }
  164. }
  165. else
  166. {
  167. //
  168. // Retrieve name of primary domain controller for specified domain.
  169. // Cannot use NetGetAnyDCName because this function will only work
  170. // with trusted domains therefore must use NetGetDCName which
  171. // always returns the PDC name.
  172. //
  173. PWSTR pszName = NULL;
  174. dwError = NetGetDCName(NULL, pszDomainName, (LPBYTE*)&pszName);
  175. if (dwError == ERROR_SUCCESS)
  176. {
  177. strNameDns = (LPCTSTR)NULL;
  178. strNameFlat = pszName;
  179. }
  180. if (pszName)
  181. {
  182. NetApiBufferFree(pszName);
  183. }
  184. }
  185. if (hNetApi32)
  186. {
  187. FreeLibrary(hNetApi32);
  188. }
  189. return dwError;
  190. }
  191. //-----------------------------------------------------------------------------
  192. // GetDcName5 Function
  193. //
  194. // Synopsis
  195. // Retrieves the DNS and flat (NetBIOS) names of a domain controller in the
  196. // specified domain.
  197. //
  198. // Note that this function is for use in code that is only loaded on W2K or
  199. // later machines. If code may loaded on NT4 or earlier machines then use
  200. // GetDcName4 function instead.
  201. //
  202. // Arguments
  203. // IN pszDomainName - the DNS or NetBIOS name of the domain or null which means
  204. // the domain that this machine belongs to
  205. // IN ulFlags - DsGetDcName option flags
  206. // OUT strNameDns - if available, the DNS name of a domain controller
  207. // OUT strNameFlat - if available, the flat name of a domain controller
  208. //
  209. // Return Value
  210. // A Win32 error code.
  211. //-----------------------------------------------------------------------------
  212. DWORD __stdcall GetDcName5(PCWSTR pszDomainName, ULONG ulFlags, _bstr_t& strNameDns, _bstr_t& strNameFlat)
  213. {
  214. ULONG ul = ulFlags & ~(DS_RETURN_DNS_NAME|DS_RETURN_FLAT_NAME);
  215. PDOMAIN_CONTROLLER_INFO pdciInfo = NULL;
  216. DWORD dwError = DsGetDcName(NULL, pszDomainName, NULL, NULL, ul, &pdciInfo);
  217. if (dwError == ERROR_SUCCESS)
  218. {
  219. if (pdciInfo->Flags & DS_DS_FLAG)
  220. {
  221. if (pdciInfo->Flags & DS_DNS_CONTROLLER_FLAG)
  222. {
  223. strNameDns = pdciInfo->DomainControllerName;
  224. NetApiBufferFree(pdciInfo);
  225. pdciInfo = NULL;
  226. dwError = DsGetDcName(NULL, pszDomainName, NULL, NULL, ul | DS_RETURN_FLAT_NAME, &pdciInfo);
  227. if (dwError == ERROR_SUCCESS)
  228. {
  229. strNameFlat = pdciInfo->DomainControllerName;
  230. }
  231. }
  232. else
  233. {
  234. strNameFlat = pdciInfo->DomainControllerName;
  235. NetApiBufferFree(pdciInfo);
  236. pdciInfo = NULL;
  237. dwError = DsGetDcName(NULL, pszDomainName, NULL, NULL, ul | DS_RETURN_DNS_NAME, &pdciInfo);
  238. if (dwError == ERROR_SUCCESS)
  239. {
  240. strNameDns = pdciInfo->DomainControllerName;
  241. }
  242. }
  243. }
  244. else
  245. {
  246. strNameDns = (LPCTSTR)NULL;
  247. strNameFlat = pdciInfo->DomainControllerName;
  248. }
  249. }
  250. if (pdciInfo)
  251. {
  252. NetApiBufferFree(pdciInfo);
  253. }
  254. return dwError;
  255. }
  256. //----------------------------------------------------------------------------
  257. // GetGlobalCatalogServer4 Function
  258. //
  259. // Synopsis
  260. // Retrieves the name of a global catalog server for the specified domain.
  261. //
  262. // Arguments
  263. // pszDomainName - the NetBIOS or DNS name of the domain
  264. // strServer - DNS name of global catalog server
  265. //
  266. // Return Value
  267. // Win32 error code.
  268. //----------------------------------------------------------------------------
  269. DWORD __stdcall GetGlobalCatalogServer4(PCWSTR pszDomainName, _bstr_t& strServer)
  270. {
  271. DWORD dwError = ERROR_SUCCESS;
  272. //
  273. // must load procedures explicitly as this component
  274. // must be loadable on Windows NT4 machines as well
  275. // even though this code is not used on remote agents
  276. //
  277. PDSGETDCNAME DsGetDcName = NULL;
  278. HMODULE hNetApi32 = LoadLibrary(L"NetApi32.dll");
  279. if (hNetApi32)
  280. {
  281. DsGetDcName = (PDSGETDCNAME)GetProcAddress(hNetApi32, "DsGetDcNameW");
  282. }
  283. else
  284. {
  285. dwError = GetLastError();
  286. }
  287. if (DsGetDcName)
  288. {
  289. //
  290. // retrieve name of domain controller for specified domain
  291. //
  292. PDOMAIN_CONTROLLER_INFO pdciDomain;
  293. dwError = DsGetDcName(
  294. NULL, pszDomainName, NULL, NULL,
  295. DS_DIRECTORY_SERVICE_REQUIRED|DS_RETURN_DNS_NAME,
  296. &pdciDomain
  297. );
  298. if (dwError == NO_ERROR)
  299. {
  300. //
  301. // retrieve name of global catalog domain controller for specified forest
  302. //
  303. PDOMAIN_CONTROLLER_INFO pdciForest;
  304. dwError = DsGetDcName(NULL, pdciDomain->DnsForestName, NULL, NULL, DS_GC_SERVER_REQUIRED, &pdciForest);
  305. if (dwError == NO_ERROR)
  306. {
  307. //
  308. // remove leading \\ so callers don't have to remove
  309. //
  310. PWSTR pszServer = pdciForest->DomainControllerName;
  311. if (pszServer && (pszServer[0] == L'\\') && (pszServer[1] == L'\\'))
  312. {
  313. strServer = pszServer + 2;
  314. }
  315. else
  316. {
  317. strServer = pszServer;
  318. }
  319. NetApiBufferFree(pdciForest);
  320. }
  321. NetApiBufferFree(pdciDomain);
  322. }
  323. }
  324. else
  325. {
  326. dwError = GetLastError();
  327. }
  328. if (hNetApi32)
  329. {
  330. FreeLibrary(hNetApi32);
  331. }
  332. return dwError;
  333. }
  334. //----------------------------------------------------------------------------
  335. // GetGlobalCatalogServer5 Function
  336. //
  337. // Synopsis
  338. // Retrieves the name of a global catalog server for the specified domain.
  339. //
  340. // Arguments
  341. // pszDomainName - the NetBIOS or DNS name of the domain
  342. // strServer - DNS name of global catalog server
  343. //
  344. // Return Value
  345. // Win32 error code.
  346. //----------------------------------------------------------------------------
  347. DWORD __stdcall GetGlobalCatalogServer5(PCWSTR pszDomainName, _bstr_t& strServer)
  348. {
  349. DWORD dwError = ERROR_SUCCESS;
  350. //
  351. // retrieve name of domain controller for specified domain
  352. //
  353. PDOMAIN_CONTROLLER_INFO pdciDomain;
  354. dwError = DsGetDcName(
  355. NULL, pszDomainName, NULL, NULL,
  356. DS_DIRECTORY_SERVICE_REQUIRED|DS_RETURN_DNS_NAME,
  357. &pdciDomain
  358. );
  359. if (dwError == NO_ERROR)
  360. {
  361. //
  362. // retrieve name of global catalog domain controller for specified forest
  363. //
  364. PDOMAIN_CONTROLLER_INFO pdciForest;
  365. dwError = DsGetDcName(NULL, pdciDomain->DnsForestName, NULL, NULL, DS_GC_SERVER_REQUIRED, &pdciForest);
  366. if (dwError == NO_ERROR)
  367. {
  368. //
  369. // remove leading \\ so callers don't have to remove
  370. //
  371. PWSTR pszServer = pdciForest->DomainControllerName;
  372. if (pszServer && (pszServer[0] == L'\\') && (pszServer[1] == L'\\'))
  373. {
  374. strServer = pszServer + 2;
  375. }
  376. else
  377. {
  378. strServer = pszServer;
  379. }
  380. NetApiBufferFree(pdciForest);
  381. }
  382. NetApiBufferFree(pdciDomain);
  383. }
  384. return dwError;
  385. }
  386. //-----------------------------------------------------------------------------
  387. // GetDomainNames4 Function
  388. //
  389. // Synopsis
  390. // Retrieves a domain's flat (NetBIOS) and DNS names given either form of the
  391. // domain name.
  392. //
  393. // Arguments
  394. // IN pszDomainName - either flat (NetBIOS) or DNS domain name
  395. // OUT strFlatName - domain flat (NetBIOS) name
  396. // OUT strDnsName - domain DNS name
  397. //
  398. // ReturnValue
  399. // The function returns DWORD Win32 error code. ERROR_SUCCESS is returned if
  400. // names are retrieved successfully.
  401. //-----------------------------------------------------------------------------
  402. DWORD __stdcall GetDomainNames4(PCWSTR pszDomainName, _bstr_t& strFlatName, _bstr_t& strDnsName)
  403. {
  404. DWORD dwError = ERROR_SUCCESS;
  405. //
  406. // must load procedures explicitly as this component
  407. // must be loadable on Windows NT4 machines as well
  408. // even though this code is not used on remote agents
  409. //
  410. #if 0
  411. PDSROLEGETPRIMARYDOMAININFORMATION pDsRoleGetPrimaryDomainInformation = NULL;
  412. PDSROLEFREEMEMORY pDsRoleFreeMemory = NULL;
  413. HMODULE hNetApi32 = LoadLibrary(L"NetApi32.dll");
  414. if (hNetApi32)
  415. {
  416. pDsRoleGetPrimaryDomainInformation = (PDSROLEGETPRIMARYDOMAININFORMATION)GetProcAddress(hNetApi32, "DsRoleGetPrimaryDomainInformation");
  417. pDsRoleFreeMemory = (PDSROLEFREEMEMORY)GetProcAddress(hNetApi32, "DsRoleFreeMemory");
  418. }
  419. if (pDsRoleGetPrimaryDomainInformation && pDsRoleFreeMemory)
  420. {
  421. //
  422. // retrieve name of domain controller for specified domain
  423. // and then retrieve the domain's DNS and NetBIOS names
  424. //
  425. _bstr_t strDomainControllerName;
  426. DWORD dwError = GetDcName4(pszDomainName, DS_DIRECTORY_SERVICE_PREFERRED, strDomainControllerName);
  427. if (dwError == NO_ERROR)
  428. {
  429. PDSROLE_PRIMARY_DOMAIN_INFO_BASIC ppdib;
  430. dwError = pDsRoleGetPrimaryDomainInformation(
  431. strDomainControllerName,
  432. DsRolePrimaryDomainInfoBasic,
  433. (BYTE**)&ppdib
  434. );
  435. if (dwError == NO_ERROR)
  436. {
  437. strDnsName = ppdib->DomainNameDns;
  438. strFlatName = ppdib->DomainNameFlat;
  439. pDsRoleFreeMemory(ppdib);
  440. }
  441. }
  442. }
  443. #else
  444. strDnsName = (LPCTSTR)NULL;
  445. strFlatName = (LPCTSTR)NULL;
  446. PDSGETDCNAME pDsGetDcName = NULL;
  447. HMODULE hNetApi32 = LoadLibrary(L"NetApi32.dll");
  448. if (hNetApi32)
  449. {
  450. pDsGetDcName = (PDSGETDCNAME)GetProcAddress(hNetApi32, "DsGetDcNameW");
  451. }
  452. //
  453. // If address of DsGetDcName function obtained then use
  454. // this API otherwise use NetGetDCName function.
  455. //
  456. if (pDsGetDcName)
  457. {
  458. PDOMAIN_CONTROLLER_INFO pdciInfo = NULL;
  459. DWORD dwError = pDsGetDcName(NULL, pszDomainName, NULL, NULL, DS_DIRECTORY_SERVICE_PREFERRED, &pdciInfo);
  460. if (dwError == ERROR_SUCCESS)
  461. {
  462. if (pdciInfo->Flags & DS_DS_FLAG)
  463. {
  464. if (pdciInfo->Flags & DS_DNS_DOMAIN_FLAG)
  465. {
  466. strDnsName = pdciInfo->DomainName;
  467. NetApiBufferFree(pdciInfo);
  468. pdciInfo = NULL;
  469. dwError = pDsGetDcName(NULL, pszDomainName, NULL, NULL, DS_RETURN_FLAT_NAME, &pdciInfo);
  470. if (dwError == ERROR_SUCCESS)
  471. {
  472. strFlatName = pdciInfo->DomainName;
  473. }
  474. }
  475. else
  476. {
  477. strFlatName = pdciInfo->DomainName;
  478. NetApiBufferFree(pdciInfo);
  479. pdciInfo = NULL;
  480. dwError = pDsGetDcName(NULL, pszDomainName, NULL, NULL, DS_RETURN_DNS_NAME, &pdciInfo);
  481. if (dwError == ERROR_SUCCESS)
  482. {
  483. strDnsName = pdciInfo->DomainName;
  484. }
  485. }
  486. }
  487. else
  488. {
  489. strFlatName = pdciInfo->DomainName;
  490. }
  491. }
  492. if (pdciInfo)
  493. {
  494. NetApiBufferFree(pdciInfo);
  495. }
  496. }
  497. else
  498. {
  499. strFlatName = pszDomainName;
  500. }
  501. #endif
  502. if (hNetApi32)
  503. {
  504. FreeLibrary(hNetApi32);
  505. }
  506. return dwError;
  507. }
  508. //-----------------------------------------------------------------------------
  509. // GetDomainNames5 Function
  510. //
  511. // Synopsis
  512. // Retrieves a domain's flat (NetBIOS) and DNS names given either form of the
  513. // domain name.
  514. //
  515. // Arguments
  516. // IN pszName - either flat (NetBIOS) or DNS domain name
  517. // OUT strFlatName - domain flat (NetBIOS) name
  518. // OUT strDnsName - domain DNS name
  519. //
  520. // ReturnValue
  521. // The function returns DWORD Win32 error code. ERROR_SUCCESS is returned if
  522. // names are retrieved successfully.
  523. //-----------------------------------------------------------------------------
  524. DWORD __stdcall GetDomainNames5(PCWSTR pszDomainName, _bstr_t& strFlatName, _bstr_t& strDnsName)
  525. {
  526. #if 0
  527. //
  528. // Retrieve name of domain controller for specified domain
  529. // and then retrieve the domain's DNS and flat (NetBIOS) names.
  530. //
  531. _bstr_t strDomainControllerName;
  532. DWORD dwError = GetDcName5(pszDomainName, DS_DIRECTORY_SERVICE_PREFERRED, strDomainControllerName);
  533. if (dwError == NO_ERROR)
  534. {
  535. PDSROLE_PRIMARY_DOMAIN_INFO_BASIC ppdib;
  536. dwError = DsRoleGetPrimaryDomainInformation(
  537. strDomainControllerName,
  538. DsRolePrimaryDomainInfoBasic,
  539. (PBYTE*)&ppdib
  540. );
  541. if (dwError == NO_ERROR)
  542. {
  543. strDnsName = ppdib->DomainNameDns;
  544. strFlatName = ppdib->DomainNameFlat;
  545. DsRoleFreeMemory(ppdib);
  546. }
  547. }
  548. return dwError;
  549. #else
  550. strDnsName = (LPCTSTR)NULL;
  551. strFlatName = (LPCTSTR)NULL;
  552. PDOMAIN_CONTROLLER_INFO pdciInfo = NULL;
  553. DWORD dwError = DsGetDcName(NULL, pszDomainName, NULL, NULL, DS_DIRECTORY_SERVICE_PREFERRED, &pdciInfo);
  554. if (dwError == ERROR_SUCCESS)
  555. {
  556. if (pdciInfo->Flags & DS_DS_FLAG)
  557. {
  558. if (pdciInfo->Flags & DS_DNS_DOMAIN_FLAG)
  559. {
  560. strDnsName = pdciInfo->DomainName;
  561. NetApiBufferFree(pdciInfo);
  562. pdciInfo = NULL;
  563. dwError = DsGetDcName(NULL, pszDomainName, NULL, NULL, DS_RETURN_FLAT_NAME, &pdciInfo);
  564. if (dwError == ERROR_SUCCESS)
  565. {
  566. strFlatName = pdciInfo->DomainName;
  567. }
  568. }
  569. else
  570. {
  571. strFlatName = pdciInfo->DomainName;
  572. NetApiBufferFree(pdciInfo);
  573. pdciInfo = NULL;
  574. dwError = DsGetDcName(NULL, pszDomainName, NULL, NULL, DS_RETURN_DNS_NAME, &pdciInfo);
  575. if (dwError == ERROR_SUCCESS)
  576. {
  577. strDnsName = pdciInfo->DomainName;
  578. }
  579. }
  580. }
  581. else
  582. {
  583. strFlatName = pdciInfo->DomainName;
  584. }
  585. }
  586. if (pdciInfo)
  587. {
  588. NetApiBufferFree(pdciInfo);
  589. }
  590. return dwError;
  591. #endif
  592. }
  593. //-----------------------------------------------------------------------------
  594. // GetRidPoolAllocator Function
  595. //
  596. // Synopsis
  597. // Retrieves the name of the domain controller in the domain that holds the
  598. // RID master role. Both the DNS and NetBIOS names are returned.
  599. //
  600. // Arguments
  601. // IN pszName - either flat (NetBIOS) or DNS domain name
  602. // OUT strDnsName - domain controller DNS name
  603. // OUT strFlatName - domain controller flat (NetBIOS) name
  604. //
  605. // ReturnValue
  606. // The function returns an HRESULT. S_OK is returned if names are retrieved
  607. // successfully.
  608. //-----------------------------------------------------------------------------
  609. HRESULT __stdcall GetRidPoolAllocator4(PCWSTR pszDomainName, _bstr_t& strDnsName, _bstr_t& strFlatName)
  610. {
  611. //
  612. // Load APIs explicitly so that this code may run in a NT4 loadable component.
  613. //
  614. CApi<PDSBIND> DsBindApi(L"NtDsApi.dll", "DsBindW");
  615. CApi<PDSUNBIND> DsUnBindApi(L"NtDsApi.dll", "DsUnBindW");
  616. CApi<PDSLISTROLES> DsListRolesApi(L"NtDsApi.dll", "DsListRolesW");
  617. CApi<PDSFREENAMERESULT> DsFreeNameResultApi(L"NtDsApi.dll", "DsFreeNameResultW");
  618. CApi<PADSGETOBJECT> ADsGetObjectApi(L"ActiveDs.dll", "ADsGetObject");
  619. DWORD dwError;
  620. if (DsBindApi.GetLastError() != ERROR_SUCCESS)
  621. {
  622. dwError = DsBindApi.GetLastError();
  623. }
  624. else if (DsUnBindApi.GetLastError() != ERROR_SUCCESS)
  625. {
  626. dwError = DsUnBindApi.GetLastError();
  627. }
  628. else if (DsListRolesApi.GetLastError() != ERROR_SUCCESS)
  629. {
  630. dwError = DsListRolesApi.GetLastError();
  631. }
  632. else if (DsFreeNameResultApi.GetLastError() != ERROR_SUCCESS)
  633. {
  634. dwError = DsFreeNameResultApi.GetLastError();
  635. }
  636. else if (ADsGetObjectApi.GetLastError() != ERROR_SUCCESS)
  637. {
  638. dwError = ADsGetObjectApi.GetLastError();
  639. }
  640. else
  641. {
  642. dwError = ERROR_SUCCESS;
  643. }
  644. if (dwError != ERROR_SUCCESS)
  645. {
  646. return HRESULT_FROM_WIN32(dwError);
  647. }
  648. //
  649. // Retrieve the name of a domain controller in the specified domain.
  650. //
  651. _bstr_t strDcNameDns;
  652. _bstr_t strDcNameFlat;
  653. dwError = GetDcName4(pszDomainName, DS_DIRECTORY_SERVICE_REQUIRED, strDcNameDns, strDcNameFlat);
  654. if (dwError != ERROR_SUCCESS)
  655. {
  656. return HRESULT_FROM_WIN32(dwError);
  657. }
  658. //
  659. // Bind to domain controller and retrieve distinguished name of
  660. // NTDS-DSA object that is the RID owner (master) in the domain.
  661. //
  662. HANDLE hDs;
  663. dwError = DsBindApi(strDcNameDns, NULL, &hDs);
  664. if (dwError != ERROR_SUCCESS)
  665. {
  666. return HRESULT_FROM_WIN32(dwError);
  667. }
  668. PDS_NAME_RESULTW pdnrResult;
  669. dwError = DsListRolesApi(hDs, &pdnrResult);
  670. if (dwError != ERROR_SUCCESS)
  671. {
  672. DsUnBindApi(&hDs);
  673. return HRESULT_FROM_WIN32(dwError);
  674. }
  675. if (DS_ROLE_RID_OWNER >= pdnrResult->cItems)
  676. {
  677. DsFreeNameResultApi(pdnrResult);
  678. DsUnBindApi(&hDs);
  679. return E_FAIL;
  680. }
  681. DS_NAME_RESULT_ITEM& dnriItem = pdnrResult->rItems[DS_ROLE_RID_OWNER];
  682. if (dnriItem.status != DS_NAME_NO_ERROR)
  683. {
  684. DsFreeNameResultApi(pdnrResult);
  685. DsUnBindApi(&hDs);
  686. return E_FAIL;
  687. }
  688. _bstr_t strFSMORoleOwner = dnriItem.pName;
  689. DsFreeNameResultApi(pdnrResult);
  690. DsUnBindApi(&hDs);
  691. WCHAR szADsPath[LEN_Path];
  692. //
  693. // Bind to NTDS-DSA object and retrieve ADsPath of parent Server object.
  694. //
  695. IADsPtr spNTDSDSA;
  696. _bstr_t strServer;
  697. szADsPath[countof(szADsPath) - 1] = L'\0';
  698. int cch = _snwprintf(
  699. szADsPath,
  700. countof(szADsPath),
  701. L"LDAP://%s/%s",
  702. (PCWSTR)strDcNameDns + 2,
  703. (PCWSTR)strFSMORoleOwner
  704. );
  705. if ((cch < 0) || (szADsPath[countof(szADsPath) - 1] != L'\0'))
  706. {
  707. return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  708. }
  709. szADsPath[countof(szADsPath) - 1] = L'\0';
  710. HRESULT hr = ADsGetObjectApi(szADsPath, IID_IADs, (VOID**)&spNTDSDSA);
  711. if (FAILED(hr))
  712. {
  713. return hr;
  714. }
  715. BSTR bstrServer;
  716. hr = spNTDSDSA->get_Parent(&bstrServer);
  717. if (FAILED(hr))
  718. {
  719. return hr;
  720. }
  721. strServer = _bstr_t(bstrServer, false);
  722. //
  723. // Bind to Server object and retrieve distinguished name of Computer object.
  724. //
  725. IADsPtr spServer;
  726. _bstr_t strServerReference;
  727. hr = ADsGetObjectApi(strServer, IID_IADs, (VOID**)&spServer);
  728. if (FAILED(hr))
  729. {
  730. return hr;
  731. }
  732. VARIANT varServerReference;
  733. VariantInit(&varServerReference);
  734. hr = spServer->Get(L"serverReference", &varServerReference);
  735. if (FAILED(hr))
  736. {
  737. return hr;
  738. }
  739. strServerReference = _variant_t(varServerReference, false);
  740. //
  741. // Bind to Computer object and retrieve DNS host name and SAM account name.
  742. //
  743. IADsPtr spComputer;
  744. _bstr_t strDNSHostName;
  745. _bstr_t strSAMAccountName;
  746. szADsPath[countof(szADsPath) - 1] = L'\0';
  747. cch = _snwprintf(
  748. szADsPath,
  749. countof(szADsPath),
  750. L"LDAP://%s/%s",
  751. (PCWSTR)strDcNameDns + 2,
  752. (PCWSTR)strServerReference
  753. );
  754. if ((cch < 0) || (szADsPath[countof(szADsPath) - 1] != L'\0'))
  755. {
  756. return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  757. }
  758. szADsPath[countof(szADsPath) - 1] = L'\0';
  759. hr = ADsGetObjectApi(szADsPath, IID_IADs, (VOID**)&spComputer);
  760. if (FAILED(hr))
  761. {
  762. return hr;
  763. }
  764. VARIANT varDNSHostName;
  765. VariantInit(&varDNSHostName);
  766. hr = spComputer->Get(L"dNSHostName", &varDNSHostName);
  767. if (FAILED(hr))
  768. {
  769. return hr;
  770. }
  771. strDNSHostName = _variant_t(varDNSHostName, false);
  772. VARIANT varSAMAccountName;
  773. VariantInit(&varSAMAccountName);
  774. hr = spComputer->Get(L"SAMAccountName", &varSAMAccountName);
  775. if (FAILED(hr))
  776. {
  777. return hr;
  778. }
  779. strSAMAccountName = _variant_t(varSAMAccountName, false);
  780. if ((strDNSHostName.length() == 0) || (strSAMAccountName.length() == 0))
  781. {
  782. return E_OUTOFMEMORY;
  783. }
  784. // Remove trailing $ character from SAM account name.
  785. *((PWSTR)strSAMAccountName + strSAMAccountName.length() - 1) = L'\0';
  786. //
  787. // Set domain controller names.
  788. //
  789. strDnsName = strDNSHostName;
  790. strFlatName = strSAMAccountName;
  791. return S_OK;
  792. }