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.

787 lines
19 KiB

  1. /*
  2. ** Copyright (c) 1998 Microsoft Corporation
  3. ** All Rights Reserved
  4. **
  5. */
  6. #include <windows.h>
  7. #include <wchar.h>
  8. #include <objbase.h>
  9. #include <winbase.h>
  10. // Required by SSPI.H
  11. #define SECURITY_WIN32
  12. #include <sspi.h>
  13. #include <dsgetdc.h>
  14. #include <ntdsapi.h>
  15. #include <lmcons.h>
  16. #include <lmapibuf.h>
  17. #include <activeds.h>
  18. #define CWSTR_SIZE(x) (sizeof(x) - (sizeof(WCHAR) * 2))
  19. #define DWSTR_SIZE(x) ((wcslen(x) + 1) * sizeof(WCHAR))
  20. #define LICENSE_SETTINGS L"TS-Enterprise-License-Server"
  21. #define LICENSE_SETTINGS2 L"CN=TS-Enterprise-License-Server"
  22. #define LICENSE_SETTINGS_OBJECT_CLASS L"LicensingSiteSettings"
  23. #define LICENSE_SETTINGS_FORMAT L"LDAP://CN=%ws,CN=%ws,CN=%ws,%ws"
  24. #define LICENSE_SETTINGS_SIZE CWSTR_SIZE(LICENSE_SETTINGS)
  25. #define LICENSE_SETTINGS_FORMAT_SIZE CWSTR_SIZE(LICENSE_SETTINGS_FORMAT)
  26. #define SITES L"sites"
  27. #define SITES_SIZE CWSTR_SIZE(SITES)
  28. #define SITE_SERVER L"siteServer"
  29. #define SITE_FORMAT L"LDAP://CN=%ws,CN=%ws,%ws"
  30. #define SITE_FORMAT_SIZE CWSTR_SIZE(SITE_FORMAT)
  31. #define CONFIG_CNTNR L"ConfigurationNamingContext"
  32. #define ROOT_DSE_PATH L"LDAP://RootDSE"
  33. HRESULT GetLicenseSettingsObjectP(VARIANT *pvar,
  34. LPWSTR *ppwszLicenseSettings,
  35. LPWSTR *ppwszSiteName,
  36. IADs **ppADs)
  37. {
  38. HRESULT hr;
  39. DWORD dwErr;
  40. LPWSTR pwszConfigContainer;
  41. IADs * pADs = NULL;
  42. VariantInit(pvar);
  43. dwErr = DsGetSiteName(NULL, ppwszSiteName);
  44. if (dwErr != 0)
  45. {
  46. #ifdef PRIVATEDEBUG
  47. wprintf(L"DsGetSiteName failed %d - 0x%x\n",dwErr,HRESULT_FROM_WIN32(dwErr));
  48. #endif
  49. return HRESULT_FROM_WIN32(dwErr);
  50. }
  51. //
  52. // Obtain the path to the configuration container.
  53. //
  54. hr = ADsGetObject(ROOT_DSE_PATH, IID_IADs, (void **)&pADs);
  55. if (FAILED(hr)) {
  56. #ifdef PRIVATEDEBUG
  57. wprintf(L"ADsGetObject (%ws) failed 0x%x \n",ROOT_DSE_PATH,dwErr);
  58. #endif
  59. goto CleanExit;
  60. }
  61. hr = pADs->Get(CONFIG_CNTNR, pvar);
  62. if (FAILED(hr)) {
  63. #ifdef PRIVATEDEBUG
  64. wprintf(L"Get (%ws) failed 0x%x \n",CONFIG_CNTNR,hr);
  65. #endif
  66. goto CleanExit;
  67. }
  68. if (V_VT(pvar) != VT_BSTR) {
  69. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  70. #ifdef PRIVATEDEBUG
  71. wprintf(L"Bad pvar 0x%x \n",hr);
  72. #endif
  73. goto CleanExit;
  74. }
  75. pwszConfigContainer = pvar->bstrVal; // For sake of readability.
  76. //
  77. // Build the X.500 path to the LicenseSettings object.
  78. //
  79. *ppwszLicenseSettings = (LPWSTR)LocalAlloc(
  80. LPTR,
  81. LICENSE_SETTINGS_FORMAT_SIZE
  82. + LICENSE_SETTINGS_SIZE
  83. + DWSTR_SIZE(*ppwszSiteName)
  84. + SITES_SIZE
  85. + DWSTR_SIZE(pwszConfigContainer)
  86. + sizeof(WCHAR));
  87. if (*ppwszLicenseSettings == NULL) {
  88. hr = E_OUTOFMEMORY;
  89. #ifdef PRIVATEDEBUG
  90. wprintf(L"LocalAlloc failed 0x%x \n",hr);
  91. #endif
  92. goto CleanExit;
  93. }
  94. wsprintf(*ppwszLicenseSettings,
  95. LICENSE_SETTINGS_FORMAT,
  96. LICENSE_SETTINGS,
  97. *ppwszSiteName,
  98. SITES,
  99. pwszConfigContainer);
  100. hr = ADsGetObject(*ppwszLicenseSettings, IID_IADs, (void **)ppADs);
  101. CleanExit:
  102. #ifdef PRIVATEDEBUG
  103. wprintf(L"ADsGetObject (%ws) failed? 0x%x \n",*ppwszLicenseSettings,hr);
  104. #endif
  105. if (NULL != pADs) {
  106. pADs->Release();
  107. }
  108. return hr;
  109. }
  110. HRESULT
  111. GetServerPos(IADs *pADs,
  112. VARIANT *pvar,
  113. LONG *plLower,
  114. LONG *plUpper,
  115. LONG *plPos,
  116. WCHAR *ComputerName
  117. )
  118. {
  119. HRESULT hr;
  120. VARIANT var;
  121. SAFEARRAY *psaServers;
  122. VariantInit(&var);
  123. hr = pADs->GetEx(SITE_SERVER,pvar);
  124. if (FAILED(hr))
  125. {
  126. hr = S_FALSE; // already gone
  127. goto CleanExit;
  128. }
  129. psaServers = V_ARRAY(pvar);
  130. if (NULL == psaServers)
  131. {
  132. hr = S_FALSE; // already gone
  133. goto CleanExit;
  134. }
  135. hr= SafeArrayGetLBound( psaServers, 1, plLower );
  136. if (FAILED(hr))
  137. {
  138. goto CleanExit;
  139. }
  140. hr= SafeArrayGetUBound( psaServers, 1, plUpper );
  141. if (FAILED(hr))
  142. {
  143. goto CleanExit;
  144. }
  145. for( *plPos = *plLower; *plPos <= *plUpper; *plPos++ )
  146. {
  147. VariantClear( &var );
  148. hr = SafeArrayGetElement( psaServers, plPos, &var );
  149. if (SUCCEEDED(hr) && (V_VT(&var) == VT_BSTR) && (V_BSTR(&var) != NULL))
  150. {
  151. if (0 == lstrcmpi(V_BSTR(&var),ComputerName))
  152. {
  153. hr = S_OK;
  154. goto CleanExit;
  155. }
  156. }
  157. }
  158. hr = S_FALSE;
  159. CleanExit:
  160. VariantClear(&var);
  161. return hr;
  162. }
  163. extern "C"
  164. HRESULT
  165. PublishEnterpriseServer()
  166. {
  167. LPWSTR pwszSiteName = NULL;
  168. DWORD dwErr;
  169. LPWSTR pwszConfigContainer;
  170. IADs * pADs = NULL;
  171. IADs * pADs2 = NULL;
  172. IADsContainer * pADsContainer = NULL;
  173. VARIANT var;
  174. VARIANT var2;
  175. VARIANT var3;
  176. VARIANT var4;
  177. LPWSTR pwszLicenseSettings = NULL;
  178. LPWSTR pwszSite = NULL;
  179. IDispatch * pDisp = NULL;
  180. WCHAR ComputerName[MAX_PATH+1];
  181. ULONG ulen;
  182. BOOL br;
  183. HRESULT hr;
  184. LONG lLower,lUpper,lPos;
  185. SAFEARRAYBOUND sabServers;
  186. LPWSTR pwszDN = NULL;
  187. DS_NAME_RESULT * pDsResult = NULL;
  188. HANDLE hDS;
  189. LPWSTR rgpwszNames[2];
  190. DOMAIN_CONTROLLER_INFO *pDCInfo = NULL;
  191. LPWSTR pwszDomain;
  192. WCHAR wszName[MAX_PATH + 1];
  193. //
  194. // We're going to use ADSI, so initialize COM. We don't
  195. // care about OLE 1.0 so disable OLE 1 DDE
  196. //
  197. hr = CoInitializeEx(NULL,COINIT_MULTITHREADED| COINIT_DISABLE_OLE1DDE);
  198. if (FAILED(hr))
  199. {
  200. #ifdef PRIVATEDEBUG
  201. wprintf(L"CoInitializeEx failed 0x%lx\n",hr);
  202. #endif
  203. return hr;
  204. }
  205. VariantInit(&var);
  206. VariantInit(&var2);
  207. VariantInit(&var3);
  208. VariantInit(&var4);
  209. // Get the computer name of the local computer.
  210. ulen = sizeof(ComputerName) / sizeof(TCHAR);
  211. br = GetComputerName(ComputerName, &ulen);
  212. if (!br)
  213. {
  214. hr = HRESULT_FROM_WIN32(GetLastError());
  215. #ifdef PRIVATEDEBUG
  216. wprintf(L"GetComputerName failed 0x%lx\n",hr);
  217. #endif
  218. goto CleanExit;
  219. }
  220. //
  221. // Get domain name
  222. //
  223. hr = DsGetDcName(NULL,
  224. NULL,
  225. NULL,
  226. NULL,
  227. DS_DIRECTORY_SERVICE_PREFERRED | DS_RETURN_FLAT_NAME,
  228. &pDCInfo);
  229. if (hr != ERROR_SUCCESS) {
  230. #ifdef PRIVATEDEBUG
  231. wprintf(L"DsGetDcName failed 0x%lx\n",hr);
  232. #endif
  233. goto CleanExit;
  234. }
  235. pwszDomain = pDCInfo->DomainName;
  236. //
  237. // Bind to the DS (get a handle for use with DsCrackNames).
  238. //
  239. hr = DsBind(NULL, pwszDomain, &hDS);
  240. if (hr != ERROR_SUCCESS) {
  241. #ifdef PRIVATEDEBUG
  242. wprintf(L"DsBind failed 0x%lx\n",hr);
  243. #endif
  244. goto CleanExit;
  245. }
  246. //
  247. // Request the DS-DN of this server's computer object.
  248. //
  249. if (lstrlen(pwszDomain) + lstrlen(ComputerName) + 3 > sizeof(wszName) / sizeof(WCHAR))
  250. {
  251. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  252. #ifdef PRIVATEDEBUG
  253. wprintf(L"Domain or ComputerName too long\n",hr);
  254. #endif
  255. goto CleanExit;
  256. }
  257. wsprintf(wszName,
  258. L"%ws\\%ws$",
  259. pwszDomain,
  260. ComputerName);
  261. rgpwszNames[0] = wszName;
  262. rgpwszNames[1] = NULL;
  263. hr = DsCrackNames(hDS,
  264. DS_NAME_NO_FLAGS,
  265. DS_UNKNOWN_NAME,
  266. DS_FQDN_1779_NAME,
  267. 1,
  268. &rgpwszNames[0],
  269. &pDsResult);
  270. DsUnBind(&hDS);
  271. if (hr != ERROR_SUCCESS)
  272. {
  273. #ifdef PRIVATEDEBUG
  274. wprintf(L"DsCrackNames failed 0x%lx\n",hr);
  275. #endif
  276. goto CleanExit;
  277. }
  278. if (pDsResult->rItems[0].status != DS_NAME_NO_ERROR) {
  279. if (pDsResult->rItems[0].status == DS_NAME_ERROR_RESOLVING) {
  280. hr = ERROR_PATH_NOT_FOUND;
  281. }
  282. else {
  283. hr = pDsResult->rItems[0].status;
  284. }
  285. #ifdef PRIVATEDEBUG
  286. wprintf(L"DsCrackNames (%ws) result bad 0x%lx\n",ComputerName,hr);
  287. #endif
  288. goto CleanExit;
  289. }
  290. V_VT(&var3) = VT_BSTR;
  291. pwszDN = pDsResult->rItems[0].pName;
  292. V_BSTR(&var3) = SysAllocString(pwszDN);
  293. if (NULL == V_BSTR(&var3))
  294. {
  295. hr = E_OUTOFMEMORY;
  296. goto CleanExit;
  297. }
  298. hr = GetLicenseSettingsObjectP(&var,
  299. &pwszLicenseSettings,
  300. &pwszSiteName,
  301. &pADs);
  302. pwszConfigContainer = var.bstrVal;
  303. if (hr == HRESULT_FROM_WIN32(ERROR_DS_NO_SUCH_OBJECT))
  304. {
  305. // Doesn't yet exist, create it
  306. //
  307. // Build the X.500 path to the Site object.
  308. //
  309. pwszSite = (LPWSTR)LocalAlloc(LPTR,
  310. SITE_FORMAT_SIZE
  311. + DWSTR_SIZE(pwszSiteName)
  312. + SITES_SIZE
  313. + DWSTR_SIZE(pwszConfigContainer)
  314. + sizeof(WCHAR));
  315. if (pwszSite == NULL) {
  316. hr = E_OUTOFMEMORY;
  317. goto CleanExit;
  318. }
  319. wsprintf(pwszSite,
  320. SITE_FORMAT,
  321. pwszSiteName,
  322. SITES,
  323. pwszConfigContainer);
  324. hr = ADsGetObject(pwszSite,
  325. IID_IADsContainer,
  326. (void **)&pADsContainer);
  327. if (FAILED(hr)) {
  328. #ifdef PRIVATEDEBUG
  329. wprintf(L"ADsGetObject (%ws) failed 0x%lx\n",pwszSite,hr);
  330. #endif
  331. goto CleanExit;
  332. }
  333. #ifdef PRIVATEDEBUG
  334. wprintf(L"Got container (%ws)\n",pwszSite);
  335. #endif
  336. //
  337. // Create the license settings leaf object.
  338. //
  339. hr = pADsContainer->Create(LICENSE_SETTINGS_OBJECT_CLASS,
  340. LICENSE_SETTINGS2,
  341. &pDisp);
  342. if (FAILED(hr)) {
  343. #ifdef PRIVATEDEBUG
  344. wprintf(L"Create (LICENSE_SETTINGS) failed 0x%lx\n",hr);
  345. #endif
  346. goto CleanExit;
  347. }
  348. #ifdef PRIVATEDEBUG
  349. wprintf(L"Created (%ws)\n",LICENSE_SETTINGS2);
  350. #endif
  351. hr = pDisp->QueryInterface(IID_IADs,
  352. (void **)&pADs2);
  353. if (FAILED(hr)) {
  354. #ifdef PRIVATEDEBUG
  355. wprintf(L"QueryInterface failed 0x%lx\n",hr);
  356. #endif
  357. goto CleanExit;
  358. }
  359. hr = pADs2->Put(SITE_SERVER,var3);
  360. if (FAILED(hr)) {
  361. #ifdef PRIVATEDEBUG
  362. wprintf(L"Put (%ws) failed 0x%lx\n",SITE_SERVER,hr);
  363. #endif
  364. goto CleanExit;
  365. }
  366. //
  367. // Persist the change via SetInfo.
  368. //
  369. hr = pADs2->SetInfo();
  370. if (FAILED(hr)) {
  371. #ifdef PRIVATEDEBUG
  372. wprintf(L"SetInfo (%ws)=(%ws) failed 0x%lx\n",SITE_SERVER,V_BSTR(&var3),hr);
  373. #endif
  374. goto CleanExit;
  375. }
  376. } else if (SUCCEEDED(hr))
  377. {
  378. // Already exists; update it
  379. hr = GetServerPos(pADs,&var2,&lLower,&lUpper,&lPos,pwszDN);
  380. if (FAILED(hr) || (hr == S_OK))
  381. {
  382. #ifdef PRIVATEDEBUG
  383. wprintf(L"GetServerPos failed ? 0x%lx\n",hr);
  384. #endif
  385. goto CleanExit;
  386. }
  387. hr = ADsBuildVarArrayStr( &(V_BSTR(&var3)), 1, &var4);
  388. if (FAILED(hr)) {
  389. #ifdef PRIVATEDEBUG
  390. wprintf(L"ADsBuildVarArrayStr (%ws) failed 0x%lx\n",V_BSTR(&var3),hr);
  391. #endif
  392. goto CleanExit;
  393. }
  394. hr = pADs->PutEx(ADS_PROPERTY_APPEND,SITE_SERVER,var4);
  395. if (FAILED(hr)) {
  396. #ifdef PRIVATEDEBUG
  397. wprintf(L"PutEx (%ws)=(%ws) failed 0x%lx\n",SITE_SERVER,V_BSTR(&var3),hr);
  398. #endif
  399. goto CleanExit;
  400. }
  401. hr = pADs->SetInfo();
  402. if (FAILED(hr)) {
  403. #ifdef PRIVATEDEBUG
  404. wprintf(L"SetInfo 2 failed 0x%lx\n",hr);
  405. #endif
  406. goto CleanExit;
  407. }
  408. } else
  409. {
  410. #ifdef PRIVATEDEBUG
  411. wprintf(L"GetLicenseSettingsObject failed 0x%lx\n",hr);
  412. #endif
  413. goto CleanExit;
  414. }
  415. CleanExit:
  416. VariantClear(&var);
  417. VariantClear(&var2);
  418. VariantClear(&var3);
  419. VariantClear(&var4);
  420. if (pwszSiteName != NULL) { // Allocated from DsGetSiteName
  421. NetApiBufferFree(pwszSiteName);
  422. }
  423. if (pwszLicenseSettings != NULL) {
  424. LocalFree(pwszLicenseSettings);
  425. }
  426. if (pwszSite != NULL) {
  427. LocalFree(pwszSite);
  428. }
  429. if (NULL != pADs) {
  430. pADs->Release();
  431. }
  432. if (NULL != pADs2) {
  433. pADs2->Release();
  434. }
  435. if (NULL != pDisp) {
  436. pDisp->Release();
  437. }
  438. if (NULL != pADsContainer) {
  439. pADsContainer->Release();
  440. }
  441. if (pDsResult != NULL) {
  442. DsFreeNameResult(pDsResult);
  443. }
  444. if (pDCInfo != NULL) {
  445. NetApiBufferFree(pDCInfo); // Allocated from DsGetDcName
  446. }
  447. CoUninitialize();
  448. return hr;
  449. }
  450. extern "C"
  451. HRESULT
  452. UnpublishEnterpriseServer()
  453. {
  454. IADs * pADs = NULL;
  455. HRESULT hr;
  456. LPWSTR pwszLicenseSettings = NULL;
  457. LPWSTR pwszSiteName = NULL;
  458. VARIANT var;
  459. VARIANT var2;
  460. VARIANT var3;
  461. SAFEARRAYBOUND sabServers;
  462. WCHAR ComputerName[MAX_PATH+1];
  463. ULONG ulen;
  464. BOOL br;
  465. LONG lPos,lLower, lUpper;
  466. DS_NAME_RESULT * pDsResult = NULL;
  467. HANDLE hDS;
  468. LPWSTR rgpwszNames[2];
  469. LPWSTR pwszDN;
  470. DOMAIN_CONTROLLER_INFO *pDCInfo = NULL;
  471. LPWSTR pwszDomain;
  472. WCHAR wszName[MAX_PATH + 1];
  473. // We're going to use ADSI, so initialize COM. We don't
  474. // care about OLE 1.0 so disable OLE 1 DDE
  475. hr = CoInitializeEx(NULL,COINIT_MULTITHREADED| COINIT_DISABLE_OLE1DDE);
  476. if (FAILED(hr))
  477. {
  478. return hr;
  479. }
  480. VariantInit(&var);
  481. VariantInit(&var2);
  482. VariantInit(&var3);
  483. // Get the computer name of the local computer.
  484. ulen = sizeof(ComputerName) / sizeof(TCHAR);
  485. br=GetComputerName(ComputerName,
  486. &ulen);
  487. if (!br)
  488. {
  489. hr = HRESULT_FROM_WIN32(GetLastError());
  490. goto CleanExit;
  491. }
  492. //
  493. // Get domain name
  494. //
  495. hr = DsGetDcName(NULL,
  496. NULL,
  497. NULL,
  498. NULL,
  499. DS_DIRECTORY_SERVICE_PREFERRED | DS_RETURN_FLAT_NAME,
  500. &pDCInfo);
  501. if (hr != ERROR_SUCCESS) {
  502. #ifdef PRIVATEDEBUG
  503. wprintf(L"DsGetDcName failed 0x%lx\n",hr);
  504. #endif
  505. goto CleanExit;
  506. }
  507. pwszDomain = pDCInfo->DomainName;
  508. //
  509. // Bind to the DS (get a handle for use with DsCrackNames).
  510. //
  511. hr = DsBind(NULL, pwszDomain, &hDS);
  512. if (hr != ERROR_SUCCESS) {
  513. #ifdef PRIVATEDEBUG
  514. wprintf(L"DsBind failed 0x%lx\n",hr);
  515. #endif
  516. goto CleanExit;
  517. }
  518. //
  519. // Request the DS-DN of this server's computer object.
  520. //
  521. if (lstrlen(pwszDomain) + lstrlen(ComputerName) + 3 > sizeof(wszName) / sizeof(WCHAR))
  522. {
  523. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  524. #ifdef PRIVATEDEBUG
  525. wprintf(L"Domain or ComputerName too long\n",hr);
  526. #endif
  527. goto CleanExit;
  528. }
  529. wsprintf(wszName,
  530. L"%ws\\%ws$",
  531. pwszDomain,
  532. ComputerName);
  533. rgpwszNames[0] = wszName;
  534. rgpwszNames[1] = NULL;
  535. hr = DsCrackNames(hDS,
  536. DS_NAME_NO_FLAGS,
  537. DS_UNKNOWN_NAME,
  538. DS_FQDN_1779_NAME,
  539. 1,
  540. &rgpwszNames[0],
  541. &pDsResult);
  542. DsUnBind(&hDS);
  543. if (hr != ERROR_SUCCESS)
  544. {
  545. #ifdef PRIVATEDEBUG
  546. wprintf(L"DsCrackNames failed 0x%lx\n",hr);
  547. #endif
  548. goto CleanExit;
  549. }
  550. if (pDsResult->rItems[0].status != DS_NAME_NO_ERROR) {
  551. if (pDsResult->rItems[0].status == DS_NAME_ERROR_RESOLVING) {
  552. hr = ERROR_PATH_NOT_FOUND;
  553. }
  554. else {
  555. hr = pDsResult->rItems[0].status;
  556. }
  557. #ifdef PRIVATEDEBUG
  558. wprintf(L"DsCrackNames result bad 0x%lx\n",hr);
  559. #endif
  560. goto CleanExit;
  561. }
  562. V_VT(&var3) = VT_BSTR;
  563. pwszDN = pDsResult->rItems[0].pName;
  564. V_BSTR(&var3) = SysAllocString(pwszDN);
  565. if (NULL == V_BSTR(&var3))
  566. {
  567. hr = E_OUTOFMEMORY;
  568. goto CleanExit;
  569. }
  570. hr = GetLicenseSettingsObjectP(&var,
  571. &pwszLicenseSettings,
  572. &pwszSiteName,
  573. &pADs);
  574. if (hr == HRESULT_FROM_WIN32(ERROR_DS_NO_SUCH_OBJECT))
  575. {
  576. hr = S_OK; // already gone
  577. goto CleanExit;
  578. }
  579. if (FAILED(hr))
  580. {
  581. goto CleanExit;
  582. }
  583. #ifdef PRIVATEDEBUG
  584. wprintf(L"pADs %ws NULL \n",(pADs == NULL) ? L"==" : L"!=");
  585. if (NULL == pADs)
  586. {
  587. goto CleanExit;
  588. }
  589. #endif
  590. hr = GetServerPos(pADs,&var2,&lLower,&lUpper,&lPos,pwszDN);
  591. if (FAILED(hr))
  592. {
  593. goto CleanExit;
  594. }
  595. if (hr == S_FALSE)
  596. {
  597. hr = S_OK; // Already gone
  598. goto CleanExit;
  599. }
  600. if (lLower == lUpper)
  601. {
  602. // only one element, delete
  603. hr = pADs->PutEx(ADS_PROPERTY_CLEAR,SITE_SERVER,var2);
  604. if (FAILED(hr)) {
  605. goto CleanExit;
  606. }
  607. }
  608. else
  609. {
  610. if (lPos != lUpper)
  611. {
  612. // move the last element here
  613. SafeArrayGetElement(V_ARRAY(&var2),&lUpper,&var3);
  614. SafeArrayPutElement(V_ARRAY(&var2),&lPos,&var3);
  615. }
  616. sabServers.lLbound = lLower;
  617. sabServers.cElements = lUpper-lLower;
  618. SafeArrayRedim(V_ARRAY(&var2),&sabServers);
  619. hr = pADs->Put(SITE_SERVER,var2);
  620. if (FAILED(hr)) {
  621. goto CleanExit;
  622. }
  623. }
  624. hr = pADs->SetInfo();
  625. if (FAILED(hr)) {
  626. goto CleanExit;
  627. }
  628. CleanExit:
  629. VariantClear(&var);
  630. VariantClear(&var2);
  631. VariantClear(&var3);
  632. if (pwszSiteName != NULL) { // Allocated from DsGetSiteName
  633. NetApiBufferFree(pwszSiteName);
  634. }
  635. if (pwszLicenseSettings != NULL) {
  636. LocalFree(pwszLicenseSettings);
  637. }
  638. if (NULL != pADs) {
  639. pADs->Release();
  640. }
  641. if (pDCInfo != NULL) {
  642. NetApiBufferFree(pDCInfo); // Allocated from DsGetDcName
  643. }
  644. CoUninitialize();
  645. return hr;
  646. }