Source code of Windows XP (NT5)
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.

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