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.

876 lines
21 KiB

  1. /*
  2. ** Copyright (c) 1998 Microsoft Corporation
  3. ** All Rights Reserved
  4. **
  5. **
  6. */
  7. #include <windows.h>
  8. #include <objbase.h>
  9. #include <winbase.h>
  10. #include <wchar.h>
  11. // Required by SSPI.H
  12. #define SECURITY_WIN32
  13. #include <sspi.h>
  14. #include <dsgetdc.h>
  15. #include <ntdsapi.h>
  16. #include <lmcons.h>
  17. #include <lmapibuf.h>
  18. #include <activeds.h>
  19. #include "lscommon.h"
  20. #include "tlsrpc.h"
  21. #include "tlsapi.h"
  22. #include "tlsapip.h"
  23. #define CWSTR_SIZE(x) (sizeof(x) - (sizeof(WCHAR) * 2))
  24. #define DWSTR_SIZE(x) ((wcslen(x) + 1) * sizeof(WCHAR))
  25. #define LICENSE_SETTINGS L"TS-Enterprise-License-Server"
  26. #define LICENSE_SETTINGS_FORMAT L"LDAP://CN=%ws,CN=%ws,CN=%ws,%ws"
  27. #define LICENSE_SETTINGS_SIZE CWSTR_SIZE(LICENSE_SETTINGS)
  28. #define LICENSE_SETTINGS_FORMAT_SIZE CWSTR_SIZE(LICENSE_SETTINGS_FORMAT)
  29. #define SITES L"sites"
  30. #define SITES_SIZE CWSTR_SIZE(SITES)
  31. #define CONFIG_CNTNR L"ConfigurationNamingContext"
  32. #define CONFIG_CNTNR_FORMAT L"LDAP://CN=%ws,%ws"
  33. #define CONFIG_CNTNR_FORMAT_SIZE CWSTR_SIZE(CONFIG_CNTNR_FORMAT)
  34. #define ROOT_DSE_PATH L"LDAP://RootDSE"
  35. #define ADS_PATH L"ADsPath"
  36. #define SEARCH_FILTER L"(CN=TS-Enterprise-LicenseServer)"
  37. #define DNS_MACHINE_NAME L"dNSHostName"
  38. #define IS_DELETED L"isDeleted"
  39. #define SITE_SERVER L"siteServer"
  40. HRESULT GetLicenseServersFromReg(LPWSTR wszRegKey, LPWSTR *ppwszServerNames,DWORD *pcServers, LPWSTR **prgwszServers);
  41. HRESULT
  42. WriteLicenseServersToReg(LPWSTR wszRegKey, LPWSTR pwszServerNames,DWORD cchServers);
  43. extern BOOL g_fInDomain;
  44. extern "C" DWORD WINAPI
  45. TLSDisconnect(
  46. TLS_HANDLE* pphContext
  47. );
  48. //
  49. // Pre-fill the ADSI cache with only the attribute we want, then get it
  50. // Only use if exactly one attribute is needed
  51. //
  52. HRESULT
  53. GetWithGetInfoEx(
  54. IADs *pADs,
  55. LPWSTR wszAttribute,
  56. VARIANT *pvar
  57. )
  58. {
  59. HRESULT hr;
  60. hr = ADsBuildVarArrayStr( &wszAttribute, 1, pvar );
  61. if( SUCCEEDED( hr ) )
  62. {
  63. hr = pADs->GetInfoEx( *pvar, 0L );
  64. if(SUCCEEDED(hr))
  65. {
  66. hr = VariantClear( pvar );
  67. if(SUCCEEDED(hr))
  68. {
  69. BSTR bstrval = SysAllocString(wszAttribute);
  70. if(NULL == bstrval)
  71. return E_OUTOFMEMORY;
  72. hr = pADs->Get( bstrval, pvar );
  73. SysFreeString(bstrval);
  74. }
  75. }
  76. }
  77. return hr;
  78. }
  79. //
  80. // Pre-fill the ADSI cache with only the attributes we want, then get them
  81. // Only use if exactly two attributes are needed
  82. //
  83. HRESULT
  84. GetWithGetInfoEx2(
  85. IADs *pADs,
  86. LPWSTR wszAttribute1,
  87. LPWSTR wszAttribute2,
  88. VARIANT *pvar1,
  89. VARIANT *pvar2,
  90. HRESULT *phr2
  91. )
  92. {
  93. HRESULT hr;
  94. LPWSTR rgwszAttributes[] = {wszAttribute1,wszAttribute2};
  95. hr = ADsBuildVarArrayStr( rgwszAttributes, 2, pvar1 );
  96. if( SUCCEEDED( hr ) )
  97. {
  98. hr = pADs->GetInfoEx( *pvar1, 0L );
  99. if (SUCCEEDED(hr))
  100. {
  101. hr = VariantClear( pvar1 );
  102. if(SUCCEEDED(hr))
  103. {
  104. BSTR bstrval1 = SysAllocString(wszAttribute1);
  105. if(NULL == bstrval1)
  106. return E_OUTOFMEMORY;
  107. BSTR bstrval2 = SysAllocString(wszAttribute2);
  108. if( NULL == bstrval2)
  109. {
  110. SysFreeString(bstrval1);
  111. return E_OUTOFMEMORY;
  112. }
  113. hr = pADs->Get( bstrval1, pvar1 );
  114. if (SUCCEEDED(hr))
  115. {
  116. *phr2 = pADs->Get( bstrval2, pvar2 );
  117. }
  118. SysFreeString(bstrval1);
  119. SysFreeString(bstrval2);
  120. }
  121. }
  122. }
  123. return hr;
  124. }
  125. HRESULT
  126. GetExWithGetInfoEx(
  127. IADs *pADs,
  128. LPWSTR wszAttribute,
  129. VARIANT *pvar
  130. )
  131. {
  132. HRESULT hr;
  133. hr = ADsBuildVarArrayStr( &wszAttribute, 1, pvar );
  134. if( SUCCEEDED( hr ) )
  135. {
  136. hr = pADs->GetInfoEx( *pvar, 0L );
  137. if(SUCCEEDED(hr))
  138. {
  139. hr = VariantClear( pvar );
  140. if(SUCCEEDED(hr))
  141. {
  142. BSTR bstrval = SysAllocString(wszAttribute);
  143. if(NULL == bstrval)
  144. return E_OUTOFMEMORY;
  145. hr = pADs->GetEx( bstrval, pvar );
  146. SysFreeString(bstrval);
  147. }
  148. }
  149. }
  150. return hr;
  151. }
  152. HRESULT GetLicenseSettingsObject(VARIANT *pvar,
  153. LPWSTR *ppwszLicenseSettings,
  154. LPWSTR *ppwszSiteName,
  155. IADs **ppADs)
  156. {
  157. HRESULT hr;
  158. DWORD dwErr = 0;
  159. LPWSTR pwszConfigContainer;
  160. IADs * pADs = NULL;
  161. IDirectorySearch *pADsSearch = NULL;
  162. ADS_SEARCH_HANDLE hSearch = NULL;
  163. ADS_SEARCH_COLUMN Column;
  164. LPWSTR pwszAdsPath = ADS_PATH;
  165. LPWSTR pwszSitesPath = NULL;
  166. BOOL fInDomain;
  167. if (g_fInDomain == -1)
  168. {
  169. dwErr = TLSInDomain(&fInDomain,NULL);
  170. if (dwErr != NO_ERROR)
  171. return HRESULT_FROM_WIN32(dwErr);
  172. } else
  173. {
  174. fInDomain = g_fInDomain;
  175. }
  176. if (!fInDomain)
  177. {
  178. return HRESULT_FROM_WIN32(ERROR_NO_SUCH_DOMAIN);
  179. }
  180. VariantInit(pvar);
  181. //
  182. // Obtain the path to the configuration container.
  183. //
  184. hr = ADsGetObject(ROOT_DSE_PATH, IID_IADs, (void **)&pADs);
  185. if (FAILED(hr)) {
  186. #ifdef PRIVATEDEBUG
  187. wprintf(L"ADsGetObject ROOT_DSE_PATH failed 0x%lx\n",hr);
  188. #endif
  189. goto CleanExit;
  190. }
  191. BSTR bstrval = SysAllocString(CONFIG_CNTNR);
  192. if(NULL == bstrval)
  193. {
  194. hr = E_OUTOFMEMORY;
  195. goto CleanExit;
  196. }
  197. hr = pADs->Get(bstrval, pvar);
  198. SysFreeString(bstrval);
  199. if (FAILED(hr)) {
  200. #ifdef PRIVATEDEBUG
  201. wprintf(L"Get CONFIG_CNTNR failed 0x%lx\n",hr);
  202. #endif
  203. goto CleanExit;
  204. }
  205. if (V_VT(pvar) != VT_BSTR) {
  206. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  207. #ifdef PRIVATEDEBUG
  208. wprintf(L"bad variant 0x%lx\n",hr);
  209. #endif
  210. goto CleanExit;
  211. }
  212. pwszConfigContainer = pvar->bstrVal; // For sake of readability.
  213. //
  214. // Get the site name, if possible
  215. //
  216. dwErr = DsGetSiteName(NULL, ppwszSiteName);
  217. if (dwErr == 0)
  218. {
  219. //
  220. // Build the X.500 path to the LicenseSettings object.
  221. //
  222. *ppwszLicenseSettings =
  223. (LPWSTR)LocalAlloc(
  224. LPTR,
  225. LICENSE_SETTINGS_FORMAT_SIZE
  226. + LICENSE_SETTINGS_SIZE
  227. + DWSTR_SIZE(*ppwszSiteName)
  228. + SITES_SIZE
  229. + DWSTR_SIZE(pwszConfigContainer)
  230. + sizeof(TCHAR));
  231. if (*ppwszLicenseSettings == NULL) {
  232. hr = E_OUTOFMEMORY;
  233. goto CleanExit;
  234. }
  235. swprintf(*ppwszLicenseSettings,
  236. LICENSE_SETTINGS_FORMAT,
  237. LICENSE_SETTINGS,
  238. *ppwszSiteName,
  239. SITES,
  240. pwszConfigContainer);
  241. hr = ADsGetObject(*ppwszLicenseSettings, IID_IADs, (void **)ppADs);
  242. if (SUCCEEDED(hr))
  243. {
  244. // return this object
  245. goto CleanExit;
  246. }
  247. }
  248. //
  249. // None in our site (or we don't know our site)
  250. // Search all sites in GC, take first one
  251. //
  252. pwszSitesPath =
  253. (LPWSTR)LocalAlloc(
  254. LPTR,
  255. CONFIG_CNTNR_FORMAT_SIZE
  256. + SITES_SIZE
  257. + DWSTR_SIZE(pwszConfigContainer)
  258. + sizeof(TCHAR));
  259. if (pwszSitesPath == NULL) {
  260. hr = E_OUTOFMEMORY;
  261. goto CleanExit;
  262. }
  263. swprintf(pwszSitesPath,
  264. CONFIG_CNTNR_FORMAT,
  265. SITES,
  266. pwszConfigContainer);
  267. hr = ADsGetObject(pwszSitesPath,
  268. IID_IDirectorySearch,
  269. (void **)&pADsSearch);
  270. if (FAILED(hr))
  271. {
  272. #ifdef PRIVATEDEBUG
  273. wprintf(L"ADsGetObject ConfigContainer (%s) failed 0x%lx\n",pwszConfigContainer,hr);
  274. #endif
  275. goto CleanExit;
  276. }
  277. hr = pADsSearch->ExecuteSearch(SEARCH_FILTER,&pwszAdsPath,1,&hSearch);
  278. if (FAILED(hr))
  279. {
  280. #ifdef PRIVATEDEBUG
  281. wprintf(L"ExecuteSearch failed 0x%lx\n",hr);
  282. #endif
  283. goto CleanExit;
  284. }
  285. hr = pADsSearch->GetNextRow(hSearch);
  286. if (hr == S_ADS_NOMORE_ROWS)
  287. hr = E_ADS_PROPERTY_NOT_SET;
  288. if (FAILED(hr))
  289. {
  290. #ifdef PRIVATEDEBUG
  291. wprintf(L"GetNextRow failed 0x%lx\n",hr);
  292. #endif
  293. goto CleanExit;
  294. }
  295. hr = pADsSearch->GetColumn(hSearch,pwszAdsPath,&Column);
  296. if (FAILED(hr))
  297. {
  298. #ifdef PRIVATEDEBUG
  299. wprintf(L"GetColumn (%ws) failed 0x%lx\n",pwszAdsPath,hr);
  300. #endif
  301. goto CleanExit;
  302. }
  303. hr = ADsGetObject(Column.pADsValues->CaseIgnoreString,
  304. IID_IADs,
  305. (void **)ppADs);
  306. pADsSearch->FreeColumn(&Column);
  307. CleanExit:
  308. if (NULL != pADs) {
  309. pADs->Release();
  310. }
  311. if (NULL != pADsSearch) {
  312. if (hSearch != NULL) {
  313. pADsSearch->CloseSearchHandle(hSearch);
  314. }
  315. pADsSearch->Release();
  316. }
  317. if (NULL != pwszSitesPath)
  318. {
  319. LocalFree(pwszSitesPath);
  320. }
  321. return hr;
  322. }
  323. HRESULT
  324. GetRandomServer(IADs *pADs,
  325. VARIANT *pvar
  326. )
  327. {
  328. HRESULT hr;
  329. VARIANT var;
  330. SAFEARRAY *psaServers;
  331. LONG lLower, lUpper, lPos;
  332. VariantInit(&var);
  333. hr = GetExWithGetInfoEx(pADs,SITE_SERVER,&var);
  334. if (FAILED(hr))
  335. {
  336. #ifdef PRIVATEDEBUG
  337. wprintf(L"GetEx (%ws) failed 0x%lx\n",LICENSE_SETTINGS,hr);
  338. #endif
  339. goto CleanExit;
  340. }
  341. psaServers = V_ARRAY(&var);
  342. if (NULL == psaServers)
  343. {
  344. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  345. #ifdef PRIVATEDEBUG
  346. wprintf(L"GetEx no array failed 0x%lx\n",hr);
  347. #endif
  348. goto CleanExit;
  349. }
  350. hr= SafeArrayGetLBound( psaServers, 1, &lLower );
  351. if (FAILED(hr))
  352. {
  353. #ifdef PRIVATEDEBUG
  354. wprintf(L"SafeArrayGetLBound failed 0x%lx\n",hr);
  355. #endif
  356. goto CleanExit;
  357. }
  358. hr= SafeArrayGetUBound( psaServers, 1, &lUpper );
  359. if (FAILED(hr))
  360. {
  361. #ifdef PRIVATEDEBUG
  362. wprintf(L"SafeArrayGetUBound failed 0x%lx\n",hr);
  363. #endif
  364. goto CleanExit;
  365. }
  366. srand(GetTickCount());
  367. lPos = (rand() % (lUpper - lLower + 1)) + lLower;
  368. hr = SafeArrayGetElement( psaServers, &lPos, pvar );
  369. #ifdef PRIVATEDEBUG
  370. wprintf(L"SafeArrayGetElement (%d) failed? 0x%lx\n",lPos,hr);
  371. #endif
  372. CleanExit:
  373. VariantClear(&var);
  374. return hr;
  375. }
  376. HRESULT
  377. GetAllServers(IADs *pADs,
  378. VARIANT *pvar
  379. )
  380. {
  381. HRESULT hr;
  382. hr = GetExWithGetInfoEx(pADs,SITE_SERVER,pvar);
  383. if (FAILED(hr))
  384. {
  385. #ifdef PRIVATEDEBUG
  386. wprintf(L"GetEx (%ws) failed 0x%lx\n",LICENSE_SETTINGS,hr);
  387. #endif
  388. }
  389. return hr;
  390. }
  391. HRESULT
  392. DnToFqdn(LPWSTR pwszDN, LPWSTR pwszFqdn)
  393. {
  394. LPWSTR pwszBindPath;
  395. HRESULT hr, hr2;
  396. IADs * pADs2 = NULL;
  397. VARIANT var2;
  398. VARIANT var3;
  399. VariantInit(&var2);
  400. VariantInit(&var3);
  401. //
  402. // Bind to the computer object referenced by the Site-Server property.
  403. //
  404. // LDAP:// + pwszDN + 1
  405. pwszBindPath = (LPWSTR) LocalAlloc(LPTR,
  406. (wcslen(pwszDN) + 8) * sizeof(WCHAR));
  407. if (pwszBindPath == NULL) {
  408. hr = E_OUTOFMEMORY;
  409. #ifdef PRIVATEDEBUG
  410. wprintf(L"LocalAlloc failed 0x%lx\n",hr);
  411. #endif
  412. goto CleanExit;
  413. }
  414. wsprintf(pwszBindPath, L"LDAP://%ws", pwszDN);
  415. hr = ADsOpenObject(pwszBindPath,
  416. NULL,
  417. NULL,
  418. ADS_SERVER_BIND,
  419. IID_IADs,
  420. (void **)&pADs2);
  421. LocalFree(pwszBindPath);
  422. if (FAILED(hr))
  423. {
  424. #ifdef PRIVATEDEBUG
  425. wprintf(L"ADsOpenObject failed 0x%lx\n",hr);
  426. #endif
  427. goto CleanExit;
  428. }
  429. //
  430. // Fetch the Machine-DNS-Name property.
  431. //
  432. hr = GetWithGetInfoEx2(pADs2,DNS_MACHINE_NAME, IS_DELETED, &var3, &var2, &hr2);
  433. if (FAILED(hr)) {
  434. #ifdef PRIVATEDEBUG
  435. wprintf(L"Get failed 0x%lx\n",hr);
  436. #endif
  437. goto CleanExit;
  438. }
  439. if (SUCCEEDED(hr2))
  440. {
  441. hr = VariantChangeType(&var2,&var2,0,VT_BOOL);
  442. if (FAILED(hr)) {
  443. #ifdef PRIVATEDEBUG
  444. wprintf(L"VariantChangeType failed 0x%lx\n",hr);
  445. #endif
  446. goto CleanExit;
  447. }
  448. if (V_BOOL(&var2))
  449. {
  450. // object has been deleted - pretend it isn't set
  451. hr = E_ADS_PROPERTY_NOT_SET;
  452. #ifdef PRIVATEDEBUG
  453. wprintf(L"Object deleted\n");
  454. #endif
  455. goto CleanExit;
  456. }
  457. }
  458. if (V_VT(&var3) != VT_BSTR) {
  459. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  460. #ifdef PRIVATEDEBUG
  461. wprintf(L"Get bad data 0x%lx\n",hr);
  462. #endif
  463. goto CleanExit;
  464. }
  465. wcscpy(pwszFqdn,V_BSTR(&var3));
  466. CleanExit:
  467. VariantClear(&var2);
  468. VariantClear(&var3);
  469. if (NULL != pADs2) {
  470. pADs2->Release();
  471. }
  472. return hr;
  473. }
  474. //
  475. // First call with fUseReg TRUE; if the returned server doesn't work
  476. // call again with fUseReg FALSE
  477. //
  478. extern "C"
  479. HRESULT
  480. FindEnterpriseServer(TLS_HANDLE *phBinding)
  481. {
  482. HRESULT hr;
  483. LPWSTR *rgwszServers = NULL;
  484. LPWSTR pwszServerNames = NULL;
  485. DWORD entriesread, i;
  486. if (phBinding == NULL)
  487. {
  488. hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  489. goto CleanExit;
  490. }
  491. *phBinding = NULL;
  492. hr = GetLicenseServersFromReg(ENTERPRISE_SERVER_MULTI,&pwszServerNames,&entriesread,&rgwszServers);
  493. if (FAILED(hr))
  494. {
  495. goto CleanExit;
  496. }
  497. for (i = 0; i < entriesread; i++)
  498. {
  499. TLS_HANDLE pContext=NULL;
  500. RPC_STATUS rpcStatus;
  501. DWORD dwVersion;
  502. if(!(pContext = TLSConnectToLsServer(rgwszServers[i])))
  503. {
  504. break;
  505. }
  506. rpcStatus = TLSGetVersion(pContext,&dwVersion);
  507. if (rpcStatus != RPC_S_OK)
  508. {
  509. TLSDisconnect(&pContext);
  510. continue;
  511. }
  512. //
  513. // No Beta <--> RTM server.
  514. //
  515. //
  516. // TLSIsBetaNTServer() returns TRUE if eval NT
  517. // IS_LSSERVER_RTM() returns TRUE if LS is an RTM.
  518. //
  519. if( TLSIsBetaNTServer() == IS_LSSERVER_RTM(dwVersion) )
  520. {
  521. continue;
  522. }
  523. if (!(dwVersion & TLS_VERSION_ENTERPRISE_BIT))
  524. {
  525. TLSDisconnect(&pContext);
  526. continue;
  527. }
  528. *phBinding = pContext;
  529. break;
  530. }
  531. CleanExit:
  532. if (pwszServerNames)
  533. LocalFree(pwszServerNames);
  534. if (rgwszServers)
  535. LocalFree(rgwszServers);
  536. return hr;
  537. }
  538. extern "C"
  539. HRESULT
  540. GetAllEnterpriseServers(WCHAR ***ppszServers, DWORD *pdwCount)
  541. {
  542. LPWSTR pwszSiteName = NULL;
  543. IADs * pADs = NULL;
  544. VARIANT var;
  545. VARIANT var2;
  546. LPWSTR pwszLicenseSettings = NULL;
  547. HRESULT hr;
  548. VARIANT HUGEP *pvar = NULL;
  549. LONG lLower, lUpper;
  550. int i;
  551. LPWSTR pwszRegServers = NULL;
  552. LPWSTR pwszRegServersTmp;
  553. DWORD cchServer, cchServers;
  554. int cServers = 0;
  555. if (ppszServers != NULL)
  556. *ppszServers = NULL;
  557. // We're going to use ADSI, so initialize COM. We don't
  558. // care about OLE 1.0 so disable OLE 1 DDE
  559. hr = CoInitialize(NULL);
  560. if (FAILED(hr))
  561. {
  562. return hr;
  563. }
  564. VariantInit(&var);
  565. VariantInit(&var2);
  566. hr = GetLicenseSettingsObject(&var,
  567. &pwszLicenseSettings,
  568. &pwszSiteName,
  569. &pADs);
  570. if (FAILED(hr)) {
  571. #ifdef PRIVATEDEBUG
  572. wprintf(L"GetLicenseSettingsObject failed 0x%lx\n",hr);
  573. #endif
  574. goto CleanExit;
  575. }
  576. hr = GetAllServers(pADs,&var2);
  577. if (FAILED(hr))
  578. {
  579. #ifdef PRIVATEDEBUG
  580. wprintf(L"GetAllServers failed 0x%lx\n",hr);
  581. #endif
  582. WriteLicenseServersToReg(ENTERPRISE_SERVER_MULTI,NULL,0);
  583. goto CleanExit;
  584. }
  585. hr = SafeArrayGetLBound( V_ARRAY(&var2), 1, &lLower );
  586. if (FAILED(hr))
  587. {
  588. #ifdef PRIVATEDEBUG
  589. wprintf(L"SafeArrayGetLBound failed 0x%lx\n",hr);
  590. #endif
  591. goto CleanExit;
  592. }
  593. hr = SafeArrayGetUBound( V_ARRAY(&var2), 1, &lUpper );
  594. if (FAILED(hr))
  595. {
  596. #ifdef PRIVATEDEBUG
  597. wprintf(L"SafeArrayGetUBound failed 0x%lx\n",hr);
  598. #endif
  599. goto CleanExit;
  600. }
  601. // Get a pointer to the elements of the safearray.
  602. hr = SafeArrayAccessData(V_ARRAY(&var2), (void HUGEP* FAR*)&pvar);
  603. if (FAILED(hr)) {
  604. goto CleanExit;
  605. }
  606. if (ppszServers != NULL) {
  607. *ppszServers = (WCHAR * *) LocalAlloc(LPTR,(lUpper-lLower+1) * sizeof(WCHAR *));
  608. if (*ppszServers == NULL) {
  609. hr = E_OUTOFMEMORY;
  610. #ifdef PRIVATEDEBUG
  611. wprintf(L"LocalAlloc failed 0x%lx\n",hr);
  612. #endif
  613. goto CleanExit;
  614. }
  615. }
  616. pwszRegServers = (LPWSTR) LocalAlloc(LPTR,2*sizeof(WCHAR));
  617. if (NULL == pwszRegServers)
  618. {
  619. #ifdef PRIVATEDEBUG
  620. wprintf(L"Out of memory\n");
  621. #endif
  622. hr = E_OUTOFMEMORY;
  623. goto CleanExit;
  624. }
  625. cchServers = 2;
  626. pwszRegServers[0] = pwszRegServers[1] = L'\0';
  627. for (i = 0; i < lUpper-lLower+1; i++)
  628. {
  629. WCHAR *szServer = (WCHAR *) LocalAlloc(LPTR,MAX_PATH*2);
  630. if (szServer == NULL) {
  631. hr = E_OUTOFMEMORY;
  632. #ifdef PRIVATEDEBUG
  633. wprintf(L"LocalAlloc failed 0x%lx\n",hr);
  634. #endif
  635. if (ppszServers != NULL) {
  636. for (int j = 0; j < cServers; j++)
  637. {
  638. LocalFree((*ppszServers)[j]);
  639. }
  640. LocalFree(*ppszServers);
  641. }
  642. goto CleanExit;
  643. }
  644. hr = DnToFqdn(V_BSTR(pvar+cServers),szServer);
  645. if (FAILED(hr))
  646. {
  647. #ifdef PRIVATEDEBUG
  648. wprintf(L"DnToFqdn failed 0x%lx\n",hr);
  649. #endif
  650. LocalFree(szServer);
  651. continue;
  652. }
  653. cchServer = wcslen(szServer);
  654. pwszRegServersTmp = (LPWSTR) LocalReAlloc(pwszRegServers,(cchServers+cchServer+1)*sizeof(TCHAR),LHND);
  655. if (NULL == pwszRegServersTmp)
  656. {
  657. #ifdef PRIVATEDEBUG
  658. wprintf(L"LocalReAlloc failed 0x%lx\n",hr);
  659. #endif
  660. hr = E_OUTOFMEMORY;
  661. if (ppszServers != NULL) {
  662. for (int j = 0; j < cServers; j++)
  663. {
  664. LocalFree((*ppszServers)[j]);
  665. }
  666. LocalFree(*ppszServers);
  667. }
  668. LocalFree(szServer);
  669. goto CleanExit;
  670. }
  671. pwszRegServers = pwszRegServersTmp;
  672. if (cchServers == 2)
  673. {
  674. wcscpy(pwszRegServers,szServer);
  675. cchServers += cchServer;
  676. } else
  677. {
  678. wcscpy(pwszRegServers+cchServers-1,szServer);
  679. cchServers += cchServer + 1;
  680. }
  681. pwszRegServers[cchServers-1] = L'\0';
  682. if (ppszServers != NULL)
  683. {
  684. (*ppszServers)[cServers] = szServer;
  685. }
  686. cServers++;
  687. }
  688. if (pdwCount != NULL)
  689. *pdwCount = cServers;
  690. WriteLicenseServersToReg(ENTERPRISE_SERVER_MULTI,pwszRegServers,cchServers);
  691. CleanExit:
  692. VariantClear(&var);
  693. VariantClear(&var2);
  694. if (pwszSiteName != NULL) { // Allocated from DsGetSiteName
  695. NetApiBufferFree(pwszSiteName);
  696. }
  697. if (pwszLicenseSettings != NULL) {
  698. LocalFree(pwszLicenseSettings);
  699. }
  700. if (pvar != NULL) {
  701. SafeArrayUnaccessData(V_ARRAY(&var2));
  702. }
  703. if (NULL != pADs) {
  704. pADs->Release();
  705. }
  706. if (pwszRegServers) {
  707. LocalFree(pwszRegServers);
  708. }
  709. CoUninitialize();
  710. if ((ppszServers != NULL) && (FAILED(hr)))
  711. *ppszServers = NULL;
  712. return hr;
  713. }