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.

904 lines
21 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1993.
  5. //
  6. // File: extension.cxx
  7. //
  8. // Contents: 3rd party extension mgmt functions
  9. //
  10. // History: 25-Oct-94 KrishnaG Created.
  11. //
  12. //----------------------------------------------------------------------------
  13. #include "iis.hxx"
  14. #pragma hdrstop
  15. LPCWSTR lpszTopLevel = L"SOFTWARE\\Microsoft\\ADs\\Providers\\IIS";
  16. LPCWSTR lpszExtensions = L"Extensions";
  17. PCLASS_ENTRY gpClassHead = NULL;
  18. PCLASS_ENTRY
  19. BuildClassesList()
  20. {
  21. HKEY hTopLevelKey = NULL;
  22. HKEY hExtensionKey = NULL;
  23. HKEY hExtensionRootKey = NULL;
  24. HKEY hClassKey = NULL;
  25. DWORD dwIndex = 0;
  26. WCHAR lpszClassName[MAX_PATH];
  27. DWORD dwchClassName = 0;
  28. PCLASS_ENTRY pClassHead = NULL;
  29. PCLASS_ENTRY pClassEntry = NULL;
  30. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  31. lpszTopLevel,
  32. 0,
  33. KEY_READ,
  34. &hTopLevelKey
  35. ) != ERROR_SUCCESS)
  36. {
  37. goto CleanupAndExit;
  38. }
  39. if (RegOpenKeyEx(hTopLevelKey,
  40. lpszExtensions,
  41. 0,
  42. KEY_READ,
  43. &hExtensionRootKey
  44. ) != ERROR_SUCCESS)
  45. {
  46. goto CleanupAndExit;
  47. }
  48. memset(lpszClassName, 0, sizeof(lpszClassName));
  49. dwchClassName = (int) (sizeof(lpszClassName) / sizeof(WCHAR));
  50. while(RegEnumKeyEx(hExtensionRootKey,
  51. dwIndex,
  52. lpszClassName,
  53. &dwchClassName,
  54. NULL,
  55. NULL,
  56. NULL,
  57. NULL
  58. ) == ERROR_SUCCESS)
  59. {
  60. //
  61. // Read namespace
  62. //
  63. if (RegOpenKeyEx(hExtensionRootKey,
  64. lpszClassName,
  65. 0,
  66. KEY_READ,
  67. &hClassKey
  68. ) != ERROR_SUCCESS){
  69. goto CleanupAndExit;
  70. }
  71. pClassEntry = BuildClassEntry(
  72. lpszClassName,
  73. hClassKey
  74. );
  75. if (pClassEntry) {
  76. pClassEntry->pNext = pClassHead;
  77. pClassHead = pClassEntry;
  78. }
  79. if (hClassKey) {
  80. CloseHandle(hClassKey);
  81. }
  82. memset(lpszClassName, 0, sizeof(lpszClassName));
  83. dwchClassName = (int) (sizeof(lpszClassName) / sizeof(WCHAR));
  84. dwIndex++;
  85. }
  86. CleanupAndExit:
  87. if (hExtensionRootKey) {
  88. RegCloseKey(hExtensionRootKey);
  89. }
  90. if (hTopLevelKey) {
  91. RegCloseKey(hTopLevelKey);
  92. }
  93. return(pClassHead);
  94. }
  95. VOID
  96. FreeClassesList(
  97. PCLASS_ENTRY pClassHead
  98. )
  99. {
  100. PCLASS_ENTRY pDelete;
  101. while (pClassHead) {
  102. pDelete = pClassHead;
  103. pClassHead = pClassHead->pNext;
  104. FreeClassEntry(pDelete);
  105. }
  106. return;
  107. }
  108. PCLASS_ENTRY
  109. BuildClassEntry(
  110. LPWSTR lpszClassName,
  111. HKEY hClassKey
  112. )
  113. {
  114. HKEY hTopLevelKey = NULL;
  115. HKEY hExtensionKey = NULL;
  116. DWORD dwIndex = 0;
  117. DWORD dwchExtensionCLSID = 0;
  118. WCHAR lpszExtensionCLSID[MAX_PATH];
  119. PCLASS_ENTRY pClassEntry = NULL;
  120. PEXTENSION_ENTRY pExtensionHead = NULL;
  121. PEXTENSION_ENTRY pExtensionEntry = NULL;
  122. pClassEntry = (PCLASS_ENTRY)AllocADsMem(sizeof(CLASS_ENTRY));
  123. if (!pClassEntry) {
  124. goto CleanupAndExit;
  125. }
  126. wcscpy(pClassEntry->szClassName, lpszClassName);
  127. memset(lpszExtensionCLSID, 0, sizeof(lpszExtensionCLSID));
  128. dwchExtensionCLSID = (int) (sizeof(lpszExtensionCLSID) / sizeof(WCHAR));
  129. while(RegEnumKeyEx(hClassKey,
  130. dwIndex,
  131. lpszExtensionCLSID,
  132. &dwchExtensionCLSID,
  133. NULL,
  134. NULL,
  135. NULL,
  136. NULL
  137. ) == ERROR_SUCCESS)
  138. {
  139. //
  140. // Read namespace
  141. //
  142. if (RegOpenKeyEx(hClassKey,
  143. lpszExtensionCLSID,
  144. 0,
  145. KEY_READ,
  146. &hExtensionKey
  147. ) != ERROR_SUCCESS){
  148. goto CleanupAndExit;
  149. }
  150. //
  151. // Read the Interfaces that this Extension supports
  152. //
  153. pExtensionEntry = BuildExtensionEntry(
  154. lpszExtensionCLSID,
  155. hExtensionKey
  156. );
  157. if (pExtensionEntry) {
  158. wcscpy(pExtensionEntry->szExtensionCLSID, lpszExtensionCLSID);
  159. pExtensionEntry->pNext = pExtensionHead;
  160. pExtensionHead = pExtensionEntry;
  161. }
  162. if (hExtensionKey) {
  163. CloseHandle(hExtensionKey);
  164. }
  165. memset(lpszExtensionCLSID, 0, sizeof(lpszExtensionCLSID));
  166. dwchExtensionCLSID = (int) (sizeof(lpszExtensionCLSID) / sizeof(WCHAR));
  167. dwIndex++;
  168. }
  169. pClassEntry->pExtensionHead = pExtensionHead;
  170. CleanupAndExit:
  171. return(pClassEntry);
  172. }
  173. PEXTENSION_ENTRY
  174. BuildExtensionEntry(
  175. LPWSTR lpszExtensionCLSID,
  176. HKEY hExtensionKey
  177. )
  178. {
  179. PEXTENSION_ENTRY pExtensionEntry = NULL;
  180. PINTERFACE_ENTRY pInterfaceEntry = NULL;
  181. PINTERFACE_ENTRY pInterfaceHead = NULL;
  182. WCHAR lpszInterfaces[MAX_PATH];
  183. DWORD dwchInterfaces = 0;
  184. LPWSTR psz = NULL;
  185. WCHAR Interface[MAX_PATH];
  186. HRESULT hr = S_OK;
  187. pExtensionEntry = (PEXTENSION_ENTRY)AllocADsMem(sizeof(EXTENSION_ENTRY));
  188. if (!pExtensionEntry) {
  189. goto CleanupAndExit;
  190. }
  191. memset(lpszInterfaces, 0, sizeof(lpszInterfaces));
  192. dwchInterfaces = sizeof(lpszInterfaces);
  193. RegQueryValueEx(
  194. hExtensionKey,
  195. L"Interfaces",
  196. NULL,
  197. NULL,
  198. (LPBYTE) lpszInterfaces,
  199. &dwchInterfaces
  200. );
  201. psz = lpszInterfaces;
  202. while (psz && *psz) {
  203. lstrcpy(Interface, psz);
  204. // skip (length) + 1
  205. // lstrlen returns length sans '\0'
  206. pInterfaceEntry = (PINTERFACE_ENTRY)AllocADsMem(sizeof(INTERFACE_ENTRY));
  207. if (pInterfaceEntry) {
  208. wcscpy(pInterfaceEntry->szInterfaceIID, Interface);
  209. hr = IIDFromString(Interface, &(pInterfaceEntry->iid));
  210. pInterfaceEntry->pNext = pInterfaceHead;
  211. pInterfaceHead = pInterfaceEntry;
  212. }
  213. psz = psz + lstrlen(psz) + 1;
  214. }
  215. wcscpy(pExtensionEntry->szExtensionCLSID, lpszExtensionCLSID);
  216. hr = CLSIDFromString(lpszExtensionCLSID, &(pExtensionEntry->ExtCLSID));
  217. pExtensionEntry->pIID = pInterfaceHead;
  218. CleanupAndExit:
  219. return(pExtensionEntry);
  220. }
  221. void
  222. FreeInterfaceEntry(
  223. PINTERFACE_ENTRY pInterfaceEntry
  224. )
  225. {
  226. if (pInterfaceEntry) {
  227. FreeADsMem(pInterfaceEntry);
  228. }
  229. }
  230. void
  231. FreeExtensionEntry(
  232. PEXTENSION_ENTRY pExtensionEntry
  233. )
  234. {
  235. PINTERFACE_ENTRY pInterfaceEntry = NULL;
  236. PINTERFACE_ENTRY pTemp = NULL;
  237. if (pExtensionEntry) {
  238. pInterfaceEntry = pExtensionEntry->pIID;
  239. while (pInterfaceEntry) {
  240. pTemp = pInterfaceEntry->pNext;
  241. if (pInterfaceEntry) {
  242. FreeInterfaceEntry(pInterfaceEntry);
  243. }
  244. pInterfaceEntry = pTemp;
  245. }
  246. //
  247. // Now unload the Extension Object
  248. //
  249. if (pExtensionEntry->pUnknown) {
  250. //
  251. // Call non-delegating Release to release ref. count on innner
  252. // object to inner object -> inner object self destroyed.
  253. //
  254. (pExtensionEntry->pUnknown)->Release();
  255. }
  256. FreeADsMem(pExtensionEntry);
  257. }
  258. return;
  259. }
  260. void
  261. FreeClassEntry(
  262. PCLASS_ENTRY pClassEntry
  263. )
  264. {
  265. PEXTENSION_ENTRY pExtensionEntry = NULL;
  266. PEXTENSION_ENTRY pTemp = NULL;
  267. if (pClassEntry) {
  268. pExtensionEntry = pClassEntry->pExtensionHead;
  269. while (pExtensionEntry) {
  270. pTemp = pExtensionEntry->pNext;
  271. if (pExtensionEntry) {
  272. FreeExtensionEntry(pExtensionEntry);
  273. }
  274. pExtensionEntry = pTemp;
  275. }
  276. FreeADsMem(pClassEntry);
  277. }
  278. return;
  279. }
  280. PINTERFACE_ENTRY
  281. MakeCopyofInterfaceEntry(
  282. PINTERFACE_ENTRY pInterfaceEntry
  283. )
  284. {
  285. PINTERFACE_ENTRY pNewInterfaceEntry = NULL;
  286. pNewInterfaceEntry = (PINTERFACE_ENTRY)AllocADsMem(sizeof(INTERFACE_ENTRY));
  287. if (pNewInterfaceEntry) {
  288. wcscpy(pNewInterfaceEntry->szInterfaceIID, pInterfaceEntry->szInterfaceIID);
  289. memcpy(&(pNewInterfaceEntry->iid), &(pInterfaceEntry->iid), sizeof(GUID));
  290. }
  291. return(pNewInterfaceEntry);
  292. }
  293. PEXTENSION_ENTRY
  294. MakeCopyofExtensionEntry(
  295. PEXTENSION_ENTRY pExtensionEntry
  296. )
  297. {
  298. PEXTENSION_ENTRY pNewExtensionEntry = NULL;
  299. PINTERFACE_ENTRY pInterfaceEntry = NULL;
  300. PINTERFACE_ENTRY pNewInterfaceEntry = NULL;
  301. PINTERFACE_ENTRY pNewInterfaceHead = NULL;
  302. pInterfaceEntry = pExtensionEntry->pIID;
  303. while (pInterfaceEntry) {
  304. pNewInterfaceEntry = MakeCopyofInterfaceEntry(pInterfaceEntry);
  305. if (pNewInterfaceEntry) {
  306. pNewInterfaceEntry->pNext = pNewInterfaceHead;
  307. pNewInterfaceHead = pNewInterfaceEntry;
  308. }
  309. pInterfaceEntry = pInterfaceEntry->pNext;
  310. }
  311. pNewExtensionEntry = (PEXTENSION_ENTRY)AllocADsMem(sizeof(EXTENSION_ENTRY));
  312. if (pNewExtensionEntry) {
  313. wcscpy(
  314. pNewExtensionEntry->szExtensionCLSID,
  315. pExtensionEntry->szExtensionCLSID
  316. );
  317. memcpy(
  318. &(pNewExtensionEntry->ExtCLSID),
  319. &(pExtensionEntry->ExtCLSID),
  320. sizeof(GUID)
  321. );
  322. pNewExtensionEntry->pIID = pNewInterfaceHead;
  323. //
  324. // Initialize fields we won't know the values of until an instacne of
  325. // the extension is created and aggregated (loaded).
  326. //
  327. pNewExtensionEntry->pUnknown=NULL;
  328. pNewExtensionEntry->pPrivDisp=NULL;
  329. pNewExtensionEntry->pADsExt=NULL;
  330. pNewExtensionEntry->fDisp=FALSE;
  331. pNewExtensionEntry->dwExtensionID = (DWORD) -1; //invalid dwExtensionID
  332. //
  333. // let class entry handle pNext
  334. //
  335. }
  336. return(pNewExtensionEntry);
  337. }
  338. PCLASS_ENTRY
  339. MakeCopyofClassEntry(
  340. PCLASS_ENTRY pClassEntry
  341. )
  342. {
  343. PCLASS_ENTRY pNewClassEntry = NULL;
  344. PEXTENSION_ENTRY pExtensionEntry = NULL;
  345. PEXTENSION_ENTRY pNewExtensionEntry = NULL;
  346. PEXTENSION_ENTRY pNewExtensionHead = NULL;
  347. pExtensionEntry = pClassEntry->pExtensionHead;
  348. while (pExtensionEntry) {
  349. pNewExtensionEntry = MakeCopyofExtensionEntry(pExtensionEntry);
  350. if (pNewExtensionEntry) {
  351. pNewExtensionEntry->pNext = pNewExtensionHead;
  352. pNewExtensionHead = pNewExtensionEntry;
  353. }
  354. pExtensionEntry = pExtensionEntry->pNext;
  355. }
  356. pNewClassEntry = (PCLASS_ENTRY)AllocADsMem(sizeof(CLASS_ENTRY));
  357. if (pNewClassEntry) {
  358. wcscpy(pNewClassEntry->szClassName, pClassEntry->szClassName);
  359. pNewClassEntry->pExtensionHead = pNewExtensionHead;
  360. }
  361. return(pNewClassEntry);
  362. }
  363. CRITICAL_SECTION g_ExtCritSect;
  364. #define ENTER_EXTENSION_CRITSECT() EnterCriticalSection(&g_ExtCritSect)
  365. #define LEAVE_EXTENSION_CRITSECT() LeaveCriticalSection(&g_ExtCritSect)
  366. HRESULT
  367. ADSIGetExtensionList(
  368. LPWSTR pszClassName,
  369. PCLASS_ENTRY * ppClassEntry
  370. )
  371. {
  372. PCLASS_ENTRY pTempClassEntry = NULL;
  373. PCLASS_ENTRY pClassEntry = NULL;
  374. ENTER_EXTENSION_CRITSECT();
  375. pTempClassEntry = gpClassHead;
  376. while (pTempClassEntry) {
  377. if (!_wcsicmp(pTempClassEntry->szClassName, pszClassName)) {
  378. //
  379. // Make a copy of this entire extension and
  380. // hand it over to the calling entity.
  381. //
  382. pClassEntry = MakeCopyofClassEntry(pTempClassEntry);
  383. *ppClassEntry = pClassEntry;
  384. LEAVE_EXTENSION_CRITSECT();
  385. RRETURN(S_OK);
  386. }
  387. pTempClassEntry = pTempClassEntry->pNext;
  388. }
  389. *ppClassEntry = NULL;
  390. LEAVE_EXTENSION_CRITSECT();
  391. RRETURN(S_OK);
  392. }
  393. //
  394. // Instantiate extension objects listed in <pClassEntry> as aggregatees of
  395. // aggregator <pUnkOuter>. Initialize extensions with <Credentials>.
  396. //
  397. // Max Load 127 extensions. Return S_FALSE if more extension in <pClassEntry>
  398. // EXTTODO: define S_??? in future for > unloaded extension -> passed to
  399. // ADSI clients.
  400. //
  401. HRESULT
  402. ADSILoadExtensions2(
  403. IUnknown FAR * pUnkOuter,
  404. CCredentials& Credentials,
  405. PCLASS_ENTRY pClassEntry
  406. )
  407. {
  408. HRESULT hr = S_OK;
  409. PEXTENSION_ENTRY pExtEntry = NULL;
  410. DWORD dwExtensionID = MIN_EXTENSION_ID;
  411. IPrivateDispatch * pPrivDisp = NULL;
  412. LPWSTR pszUserName = NULL;
  413. LPWSTR pszPassword = NULL;
  414. DWORD dwAuthFlags = 0;
  415. VARIANT varUserName;
  416. VARIANT varPassword;
  417. VARIANT varAuthFlags;
  418. PVARIANT pvarUserName = &varUserName;
  419. PVARIANT pvarPassword = &varPassword;
  420. PVARIANT pvarAuthFlags = &varAuthFlags;
  421. BOOL fReturnError = FALSE;
  422. ASSERT(pUnkOuter);
  423. if (pClassEntry)
  424. {
  425. pExtEntry=pClassEntry->pExtensionHead;
  426. }
  427. if (!pClassEntry || !pExtEntry) {
  428. RRETURN(S_OK);
  429. }
  430. VariantInit(pvarUserName);
  431. VariantInit(pvarPassword);
  432. VariantInit(pvarAuthFlags);
  433. hr = Credentials.GetUserName(&pszUserName);
  434. if (FAILED(hr)) {
  435. RRETURN(S_OK);
  436. }
  437. hr = Credentials.GetPassword(&pszPassword);
  438. if (FAILED(hr)) {
  439. RRETURN(S_OK);
  440. }
  441. dwAuthFlags = Credentials.GetAuthFlags();
  442. while (pExtEntry) {
  443. //
  444. // Max # of extension have been loaded, cannot load more
  445. //
  446. if (dwExtensionID>MAX_EXTENSION_ID) {
  447. //
  448. // EXTTODO: S_FALSE for now. See hdr doc for future plan.
  449. //
  450. hr = S_FALSE;
  451. break;
  452. }
  453. //
  454. // create extension object (aggregatee) and ask for Non-delegating
  455. // IUnknown. Ref count on extension object = 1.
  456. //
  457. hr = CoCreateInstance(
  458. pExtEntry->ExtCLSID,
  459. pUnkOuter,
  460. CLSCTX_INPROC_SERVER,
  461. IID_IUnknown,
  462. (void **)&(pExtEntry->pUnknown)
  463. );
  464. //
  465. // if fail, go to next extesion entry s.t. bad individual extension
  466. // cannot block other extensions from loading (no clean up needed)
  467. //
  468. // EXTTODO: no warning to user about failure
  469. //
  470. if (SUCCEEDED(hr)) {
  471. pExtEntry->dwExtensionID = dwExtensionID;
  472. hr = (pExtEntry->pUnknown)->QueryInterface(
  473. IID_IADsExtension,
  474. (void **) &(pExtEntry->pADsExt)
  475. );
  476. if (FAILED(hr)) {
  477. //
  478. // extension does not support the optioanl IADsExtension -> OK.
  479. // (no clean up needed)
  480. //
  481. pExtEntry->pADsExt=NULL;
  482. pExtEntry->fDisp = FALSE;
  483. } else {
  484. //
  485. // Cache the interface ptr but call Release() immediately to
  486. // avoid aggregator having a ref count on itself
  487. // since IADsExtension inherits from delegating IUnknown.
  488. //
  489. // Note: codes still works if inherit from NonDelegatingIUknown
  490. //
  491. (pExtEntry->pADsExt)->Release() ;
  492. //
  493. // For efficiency, set this flag to FALSE on FIRST encounter of
  494. // pADsExt->PrivateGetIDsOfNames()/Invoke() returning E_NOTIMPL.
  495. // Set as TRUE now s.t. at least first encounter will happen.
  496. //
  497. pExtEntry->fDisp = TRUE;
  498. //
  499. // Pass its own credentials to extension. Ignore error if any.
  500. //
  501. hr = ADsAllocString(
  502. pszUserName,
  503. &(pvarUserName->bstrVal)
  504. );
  505. if (FAILED(hr)) {
  506. fReturnError = TRUE;
  507. BAIL_ON_FAILURE(hr);
  508. }
  509. V_VT(pvarUserName) = VT_BSTR;
  510. hr = ADsAllocString(
  511. pszPassword,
  512. &(pvarPassword->bstrVal)
  513. );
  514. if (FAILED(hr)) {
  515. fReturnError = TRUE;
  516. BAIL_ON_FAILURE(hr);
  517. }
  518. V_VT(pvarPassword) = VT_BSTR;
  519. V_I4(pvarAuthFlags) = dwAuthFlags;
  520. V_VT(pvarAuthFlags) = VT_I4;
  521. hr = (pExtEntry->pADsExt)->Operate(
  522. ADS_EXT_INITCREDENTIALS,
  523. varUserName,
  524. varPassword,
  525. varAuthFlags
  526. );
  527. }
  528. } // end if CoCreateInstance() succeeded
  529. pExtEntry = pExtEntry->pNext;
  530. //
  531. // ++ extension ID even if creat'n of extension fails just to be safe
  532. // - chuck's stuff :)
  533. //
  534. dwExtensionID++;
  535. } // end while
  536. error:
  537. if (pszUserName) {
  538. FreeADsStr(pszUserName);
  539. }
  540. if (pszPassword) {
  541. FreeADsStr(pszPassword);
  542. }
  543. VariantClear(pvarUserName);
  544. VariantClear(pvarPassword);
  545. VariantClear(pvarAuthFlags);
  546. if (fReturnError) {
  547. RRETURN(hr); // fetal error,
  548. }
  549. else {
  550. RRETURN(S_OK); // "okay" error if any, optional support
  551. }
  552. }
  553. HRESULT
  554. ADSILoadExtensions(
  555. IUnknown FAR * pUnkOuter,
  556. CCredentials& Credentials,
  557. PCLASS_ENTRY pClassEntry,
  558. LPTSTR pszClassName
  559. )
  560. {
  561. HRESULT hr = S_OK;
  562. PEXTENSION_ENTRY pExtensionEntry = NULL;
  563. DWORD dwExtensionID = 1;
  564. IPrivateDispatch * pPrivDisp = NULL;
  565. LPWSTR pszUserName = NULL;
  566. LPWSTR pszPassword = NULL;
  567. DWORD dwAuthFlags = 0;
  568. hr = Credentials.GetUserName(&pszUserName);
  569. if (FAILED(hr)) {
  570. RRETURN(S_OK);
  571. }
  572. hr = Credentials.GetPassword(&pszPassword);
  573. if (FAILED(hr)) {
  574. RRETURN(S_OK);
  575. }
  576. dwAuthFlags = Credentials.GetAuthFlags();
  577. pExtensionEntry = pClassEntry->pExtensionHead;
  578. while (pExtensionEntry) {
  579. hr = CoCreateInstance(
  580. pExtensionEntry->ExtCLSID,
  581. pUnkOuter,
  582. CLSCTX_INPROC_SERVER,
  583. IID_IPrivateUnknown,
  584. (void **)&(pExtensionEntry->pUnknown)
  585. );
  586. if (SUCCEEDED(hr)) {
  587. hr = (pExtensionEntry->pUnknown)->ADSIInitializeObject(
  588. pszUserName,
  589. pszPassword,
  590. dwAuthFlags
  591. );
  592. pExtensionEntry->dwExtensionID = dwExtensionID;
  593. hr = (pExtensionEntry->pUnknown)->QueryInterface(
  594. IID_IPrivateDispatch,
  595. (void **)&pPrivDisp
  596. );
  597. if (SUCCEEDED(hr)) {
  598. hr = pPrivDisp->ADSIInitializeDispatchManager(dwExtensionID);
  599. if (FAILED(hr)) {
  600. //
  601. // Remember NOT to do a Release here for IPrivateDispatch
  602. //
  603. pExtensionEntry->fDisp = FALSE;
  604. (pExtensionEntry->pUnknown)->Release();
  605. }else {
  606. pExtensionEntry->fDisp = TRUE;
  607. pExtensionEntry->pPrivDisp = pPrivDisp;
  608. //
  609. // Now release both pointers because we don't want to
  610. // have a cyclic reference count
  611. //
  612. (pExtensionEntry->pPrivDisp)->Release();
  613. (pExtensionEntry->pUnknown)->Release();
  614. }
  615. }else {
  616. pExtensionEntry->fDisp = FALSE;
  617. (pExtensionEntry->pUnknown)->Release();
  618. }
  619. }
  620. pExtensionEntry = pExtensionEntry->pNext;
  621. dwExtensionID++;
  622. }
  623. if (pszUserName) {
  624. FreeADsStr(pszUserName);
  625. }
  626. if (pszPassword) {
  627. FreeADsStr(pszPassword);
  628. }
  629. RRETURN(S_OK);
  630. }