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.

786 lines
20 KiB

  1. //
  2. // Author: DebiM
  3. // Date: September 1996
  4. //
  5. // File: csacc.cxx
  6. //
  7. // Class Store Manager implementation for a client desktop.
  8. //
  9. // This source file contains implementations for IClassAccess
  10. // interface for CClassAccess object.
  11. // It also contains the IEnumPackage implementation for the
  12. // aggregate of all class containers seen by the caller.
  13. //
  14. //
  15. //---------------------------------------------------------------------
  16. #include "cstore.hxx"
  17. IClassAccess *GetNextValidClassStore(CLASSCONTAINER **pStoreList,
  18. DWORD cStores,
  19. PSID pUserSid,
  20. uCLSSPEC* pClassSpec,
  21. BOOL fCache,
  22. DWORD* pcount);
  23. extern HRESULT GetUserClassStores(
  24. PCLASSCONTAINER **ppStoreList,
  25. DWORD *pcStores,
  26. BOOL *pfCache,
  27. PSID *ppUserSid);
  28. //
  29. // Link list pointer for Class Containers Seen
  30. //
  31. extern CLASSCONTAINER *gpContainerHead;
  32. //
  33. // Link list pointer for User Profiles Seen
  34. //
  35. extern USERPROFILE *gpUserHead;
  36. //
  37. // Global Class Factory for Class Container
  38. //
  39. extern CAppContainerCF *pCF;
  40. //
  41. // Critical Section used during operations on list of class stores
  42. //
  43. extern CRITICAL_SECTION ClassStoreBindList;
  44. //
  45. // CClassAccess implementation
  46. //
  47. CClassAccess::CClassAccess()
  48. {
  49. m_uRefs = 1;
  50. m_cCalls = 0;
  51. pStoreList = NULL;
  52. cStores = 0;
  53. }
  54. CClassAccess::~CClassAccess()
  55. {
  56. DWORD i;
  57. for (i = 0; i < cStores; i++)
  58. {
  59. if (pStoreList[i]->gpClassStore)
  60. {
  61. (pStoreList[i]->gpClassStore)->Release();
  62. pStoreList[i]->gpClassStore = NULL;
  63. CSDBGPrint((L"Found open container and closed."));
  64. }
  65. if (pStoreList[i]->pszClassStorePath)
  66. {
  67. CoTaskMemFree (pStoreList[i]->pszClassStorePath);
  68. pStoreList[i]->pszClassStorePath = NULL;
  69. }
  70. CoTaskMemFree(pStoreList[i]);
  71. pStoreList[i] = NULL;
  72. }
  73. CoTaskMemFree(pStoreList);
  74. cStores = NULL;
  75. }
  76. //----------------------------------------------------------------------
  77. //
  78. //
  79. void PrintClassSpec(
  80. uCLSSPEC * pclsspec // Class Spec (GUID/Ext/MIME)
  81. )
  82. {
  83. STRINGGUID szClsid;
  84. if (pclsspec->tyspec == TYSPEC_CLSID)
  85. {
  86. StringFromGUID (pclsspec->tagged_union.clsid, szClsid);
  87. CSDBGPrint((L" ... GetAppInfo by CLSID = %s", szClsid));
  88. }
  89. if (pclsspec->tyspec == TYSPEC_PROGID)
  90. {
  91. CSDBGPrint((L" ... GetAppInfo by ProgID = %s",
  92. pclsspec->tagged_union.pProgId));
  93. }
  94. if (pclsspec->tyspec == TYSPEC_MIMETYPE)
  95. {
  96. CSDBGPrint((L" ... GetAppInfo by MimeType = %s",
  97. pclsspec->tagged_union.pMimeType));
  98. }
  99. if (pclsspec->tyspec == TYSPEC_FILEEXT)
  100. {
  101. CSDBGPrint((L" ... GetAppInfo by FileExt = %s",
  102. pclsspec->tagged_union.pFileExt));
  103. }
  104. if (pclsspec->tyspec == TYSPEC_IID)
  105. {
  106. StringFromGUID (pclsspec->tagged_union.iid, szClsid);
  107. CSDBGPrint((L" ... GetAppInfo by IID = %s", szClsid));
  108. }
  109. }
  110. //----------------------------------------------------------------------
  111. HRESULT STDMETHODCALLTYPE
  112. CClassAccess::GetAppInfo(
  113. uCLSSPEC * pclsspec, // Class Spec (GUID/Ext/MIME)
  114. QUERYCONTEXT * pQryContext, // Query Attributes
  115. PACKAGEDISPINFO * pPackageInfo
  116. )
  117. //
  118. // This is the most common method to access the Class Store.
  119. // It queries the class store for implementations for a specific
  120. // Class Id, or File Ext, or ProgID or MIME type.
  121. //
  122. // If a matching implementation is available for the object type,
  123. // client architecture, locale and class context pointer to the
  124. // binary is returned.
  125. {
  126. //
  127. // Assume that this method is called in the security context
  128. // of the user process. Hence there is no need to impersonate.
  129. //
  130. //
  131. // Get the list of Class Stores for this user
  132. //
  133. HRESULT hr = S_OK;
  134. ULONG i = 0, j = 0, k= 0;
  135. IClassAccess * pICA = NULL;
  136. BOOL fCache = FALSE;
  137. PSID pUserSid = NULL;
  138. BOOL fFound = FALSE;
  139. QUERYCONTEXT QueryContext;
  140. // added later.
  141. if (gDebug)
  142. {
  143. WCHAR Name[32];
  144. DWORD NameSize = 32;
  145. if ( ! GetUserName( Name, &NameSize ) )
  146. CSDBGPrint((L"GetAppInfo GetUserName failed 0x%x", GetLastError()));
  147. else
  148. CSDBGPrint((L"GetAppInfo as %s", Name));
  149. }
  150. if ((!pPackageInfo) ||
  151. (!IsValidReadPtrIn(pPackageInfo, sizeof(PACKAGEDISPINFO))))
  152. return E_INVALIDARG;
  153. memset(pPackageInfo, 0, sizeof(PACKAGEDISPINFO));
  154. if ( pQryContext )
  155. {
  156. QueryContext = *pQryContext;
  157. }
  158. else
  159. {
  160. // gets the default information.
  161. QueryContext.dwContext = CLSCTX_ALL;
  162. GetDefaultPlatform( &QueryContext.Platform );
  163. QueryContext.Locale = MAKELCID(GetUserDefaultLangID(), SUBLANG_NEUTRAL);
  164. QueryContext.dwVersionHi = (DWORD) -1;
  165. QueryContext.dwVersionLo = (DWORD) -1;
  166. }
  167. if (gDebug)
  168. PrintClassSpec(pclsspec);
  169. if (!pStoreList)
  170. hr = GetUserClassStores(
  171. &pStoreList,
  172. &cStores,
  173. &fCache,
  174. &pUserSid);
  175. ERROR_ON_FAILURE(hr);
  176. for (i=0; i < cStores; i++)
  177. {
  178. if (!(pICA = GetNextValidClassStore(pStoreList, cStores, pUserSid, pclsspec, fCache, &i)))
  179. continue;
  180. //
  181. // Call method on this store
  182. //
  183. pICA->AddRef();
  184. hr = pICA->GetAppInfo(
  185. pclsspec,
  186. &QueryContext,
  187. pPackageInfo);
  188. // Release it after use.
  189. pICA->Release();
  190. //
  191. // Special case error return E_INVALIDARG
  192. // Do not continue to look, return this.
  193. //
  194. if (hr == E_INVALIDARG)
  195. {
  196. ERROR_ON_FAILURE(hr);
  197. }
  198. //
  199. // maintain access counters
  200. //
  201. (pStoreList[i])->cAccess++;
  202. //
  203. // We are iterating through the class stores from highest precedence to lowest --
  204. // thus, the first container to return success will be our choice.
  205. //
  206. if (SUCCEEDED(hr))
  207. {
  208. fFound = TRUE;
  209. break;
  210. }
  211. else
  212. {
  213. (pStoreList[i])->cNotFound++;
  214. CSDBGPrint((L"CClassAccess::GetAppInfo() returned 0x%x", hr));
  215. }
  216. hr = S_OK;
  217. }
  218. Error_Cleanup:
  219. if (pUserSid)
  220. CoTaskMemFree (pUserSid);
  221. if (fFound)
  222. {
  223. CSDBGPrint((L"Returning Package %s", pPackageInfo->pszPackageName));
  224. return S_OK;
  225. }
  226. if (!SUCCEEDED(hr))
  227. return hr;
  228. return CS_E_PACKAGE_NOTFOUND;
  229. }
  230. #define MAX_GUID_CCH 38
  231. //
  232. // IsClassStoreForPolicy
  233. //
  234. BOOL IsClassStoreForPolicy(CLASSCONTAINER* pClassStore,
  235. LPWSTR wszPolicyId)
  236. {
  237. LPWSTR pszPolicyGuid;
  238. // Path looks like:
  239. // LDAP://CN=<Class Store Name>,CN=<user-or-machine>,CN=<{policy-guid}>,...
  240. //
  241. // Look for ',' first
  242. //
  243. pszPolicyGuid = wcschr(pClassStore->pszClassStorePath, L',');
  244. if (!pszPolicyGuid)
  245. {
  246. return FALSE;
  247. }
  248. //
  249. // Look for the second ','
  250. //
  251. pszPolicyGuid = wcschr(pszPolicyGuid + 1, L',');
  252. if (!pszPolicyGuid)
  253. {
  254. return FALSE;
  255. }
  256. //
  257. // Now get to '{' at start of guid -- it is 4 chars
  258. // past the ',' which we are currently at. Use wcschr
  259. // to make sure we don't go past the end of the string
  260. // and that our assumptions about the structure of the
  261. // path are correct
  262. //
  263. if (wcschr(pszPolicyGuid, L'{') == (pszPolicyGuid + 4))
  264. {
  265. pszPolicyGuid += 4;
  266. //
  267. // Now that we have the '{', we are at the start of the guid
  268. // and can compare with the requested policy id
  269. //
  270. if (_wcsnicmp(pszPolicyGuid, wszPolicyId, MAX_GUID_CCH) == 0)
  271. {
  272. return TRUE;
  273. }
  274. }
  275. return FALSE;
  276. }
  277. //
  278. // GetNextValidClassStore
  279. //
  280. //
  281. IClassAccess *GetNextValidClassStore(CLASSCONTAINER** pStoreList,
  282. DWORD cStores,
  283. PSID pUserSid,
  284. uCLSSPEC* pClassSpec,
  285. BOOL fCache,
  286. DWORD * pcount)
  287. {
  288. IClassAccess *pretICA = NULL;
  289. BOOL bSpecificPolicy;
  290. LPWSTR wszPolicyGuid;
  291. HRESULT hr;
  292. wszPolicyGuid = NULL;
  293. hr = S_OK;
  294. bSpecificPolicy = pClassSpec ? TYSPEC_PACKAGENAME == pClassSpec->tyspec : FALSE;
  295. if (bSpecificPolicy)
  296. {
  297. hr = StringFromCLSID(pClassSpec->tagged_union.ByName.PolicyId, &wszPolicyGuid);
  298. }
  299. if (SUCCEEDED(hr))
  300. {
  301. for (pStoreList += (*pcount); (*pcount) < cStores; (*pcount)++, pStoreList++)
  302. {
  303. if ((*pStoreList)->gpClassStore != NULL)
  304. {
  305. break;
  306. }
  307. if (bSpecificPolicy &&
  308. !IsClassStoreForPolicy(*pStoreList, wszPolicyGuid))
  309. {
  310. continue;
  311. }
  312. if (FALSE) // ((*pStoreList)->cBindFailures >= MAX_BIND_ATTEMPTS)
  313. {
  314. // Number of continuous failures have reached MAX_BIND_ATTEMPTS
  315. // for this container.
  316. // Will temporarily disable lookups in this container.
  317. // Report it in EventLog once
  318. //
  319. if ((*pStoreList)->cBindFailures == MAX_BIND_ATTEMPTS)
  320. {
  321. //LogCsPathError((*pStoreList)->pszClassStorePath, hr);
  322. (*pStoreList)->cBindFailures++;
  323. }
  324. continue;
  325. }
  326. else
  327. {
  328. CSDBGPrint((L"CS: .. Connecting to Store %d ... %s..",
  329. (*pcount),
  330. (*pStoreList)->pszClassStorePath));
  331. //
  332. // Bind to this Class Store
  333. //
  334. if ((wcsncmp ((*pStoreList)->pszClassStorePath, L"ADCS:", 5) == 0) ||
  335. (wcsncmp ((*pStoreList)->pszClassStorePath, L"LDAP:", 5) == 0))
  336. {
  337. //
  338. // If the Storename starts with ADCS or LDAP
  339. // it is NTDS based implementation. Call directly.
  340. //
  341. IClassAccess *pCA = NULL;
  342. LPOLESTR szClassStore = (*pStoreList)->pszClassStorePath;
  343. // skipping ADCS:
  344. if (wcsncmp ((*pStoreList)->pszClassStorePath, L"ADCS:", 5) == 0)
  345. szClassStore += 5;
  346. hr = pCF->CreateConnectedInstance(
  347. szClassStore,
  348. pUserSid,
  349. fCache,
  350. (void **)&pCA);
  351. if (SUCCEEDED(hr))
  352. {
  353. EnterCriticalSection (&ClassStoreBindList);
  354. if ((*pStoreList)->gpClassStore != NULL)
  355. {
  356. pCA->Release();
  357. pCA = NULL;
  358. }
  359. else
  360. {
  361. (*pStoreList)->gpClassStore = pCA;
  362. pCA = NULL;
  363. }
  364. LeaveCriticalSection (&ClassStoreBindList);
  365. }
  366. }
  367. else
  368. {
  369. //
  370. // Support for Third Party Pluggable
  371. // Class Stores is not in Beta2.
  372. //
  373. ReportEventCS(hr = CS_E_INVALID_PATH, CS_E_INVALID_PATH, (*pStoreList)->pszClassStorePath);
  374. }
  375. if (SUCCEEDED(hr))
  376. {
  377. (*pStoreList)->cBindFailures = 0;
  378. hr = S_OK;
  379. break;
  380. }
  381. if (!SUCCEEDED(hr))
  382. {
  383. CSDBGPrint((L"Failed to connect to this store"));
  384. if ((*pStoreList)->cBindFailures == 0)
  385. {
  386. // First failue or First failure after successful
  387. // binding.
  388. // Report it in EventLog
  389. //
  390. //LogCsPathError((*pStoreList)->pszClassStorePath, hr);
  391. }
  392. ((*pStoreList)->cBindFailures) ++;
  393. continue;
  394. }
  395. }
  396. }
  397. }
  398. if (wszPolicyGuid)
  399. {
  400. CoTaskMemFree(wszPolicyGuid);
  401. }
  402. if ((*pcount) != cStores)
  403. pretICA = (*pStoreList)->gpClassStore;
  404. return pretICA;
  405. }
  406. HRESULT STDMETHODCALLTYPE CClassAccess::EnumPackages(
  407. LPOLESTR pszPackageName,
  408. GUID *pCategory,
  409. ULONGLONG *pLastUsn,
  410. DWORD dwAppFlags, // AppType options
  411. IEnumPackage **ppIEnumPackage)
  412. {
  413. //
  414. // Get the list of Class Stores for this user
  415. //
  416. HRESULT hr = S_OK;
  417. ULONG i;
  418. IEnumPackage *Enum[MAXCLASSSTORES];
  419. ULONG cEnum = 0;
  420. CMergedEnumPackage *EnumMerged = NULL;
  421. IClassAccess *pICA = NULL;
  422. ULONGLONG LastUsn, CopyLastUsn, *pCopyLastUsn;
  423. BOOL fCache = FALSE;
  424. PSID pUserSid = NULL;
  425. // added later.
  426. if (gDebug)
  427. {
  428. WCHAR Name[32];
  429. DWORD NameSize = 32;
  430. if ( ! GetUserName( Name, &NameSize ) )
  431. CSDBGPrint((L"EnumPackage GetUserName failed 0x%x", GetLastError()));
  432. else
  433. CSDBGPrint((L"EnumPackage as %s", Name));
  434. }
  435. LastUsn = 0;
  436. if (pLastUsn)
  437. {
  438. //
  439. // Check pLastUsn
  440. //
  441. if (!IsValidReadPtrIn(pLastUsn, sizeof(ULONGLONG)))
  442. return E_INVALIDARG;
  443. pCopyLastUsn = &CopyLastUsn;
  444. *pCopyLastUsn = *pLastUsn;
  445. }
  446. else
  447. pCopyLastUsn = NULL;
  448. //
  449. // Get the list of Class Stores for this user
  450. //
  451. if (!pStoreList)
  452. hr = GetUserClassStores(
  453. &pStoreList,
  454. &cStores,
  455. &fCache,
  456. &pUserSid);
  457. *ppIEnumPackage = NULL;
  458. if ((hr == S_OK) && (cStores == 0))
  459. {
  460. hr = CS_E_NO_CLASSSTORE;
  461. }
  462. if (!SUCCEEDED(hr))
  463. {
  464. //
  465. // Free the Sid
  466. //
  467. if (pUserSid)
  468. CoTaskMemFree (pUserSid);
  469. return hr;
  470. }
  471. for (i=0; i < cStores; i++)
  472. {
  473. if (!(pICA = GetNextValidClassStore(pStoreList, cStores, pUserSid, NULL, fCache, &i)))
  474. continue;
  475. //
  476. // Call method on this store
  477. //
  478. hr = pICA->EnumPackages (pszPackageName,
  479. pCategory,
  480. pCopyLastUsn,
  481. dwAppFlags,
  482. &(Enum[cEnum]));
  483. if (hr == E_INVALIDARG)
  484. {
  485. break;
  486. }
  487. if (pCopyLastUsn)
  488. {
  489. if (LastUsn < *pCopyLastUsn)
  490. LastUsn = *pCopyLastUsn;
  491. *pCopyLastUsn = *pLastUsn;
  492. }
  493. if (SUCCEEDED(hr))
  494. cEnum++;
  495. }
  496. if (SUCCEEDED(hr))
  497. {
  498. EnumMerged = new CMergedEnumPackage;
  499. hr = EnumMerged->Initialize(Enum, cEnum);
  500. if (FAILED(hr))
  501. {
  502. for (i = 0; i < cEnum; i++)
  503. Enum[i]->Release();
  504. delete EnumMerged;
  505. }
  506. else
  507. {
  508. hr = EnumMerged->QueryInterface(IID_IEnumPackage, (void **)ppIEnumPackage);
  509. if (FAILED(hr))
  510. delete EnumMerged;
  511. }
  512. if (pLastUsn)
  513. {
  514. if (LastUsn > *pLastUsn)
  515. *pLastUsn = LastUsn;
  516. }
  517. }
  518. if (pUserSid)
  519. CoTaskMemFree (pUserSid);
  520. return hr;
  521. }
  522. //--------------------------------------------------------------
  523. CMergedEnumPackage::CMergedEnumPackage()
  524. {
  525. m_pcsEnum = NULL;
  526. m_cEnum = 0;
  527. m_csnum = 0;
  528. m_dwRefCount = 0;
  529. }
  530. CMergedEnumPackage::~CMergedEnumPackage()
  531. {
  532. ULONG i;
  533. for (i = 0; i < m_cEnum; i++)
  534. m_pcsEnum[i]->Release();
  535. CoTaskMemFree(m_pcsEnum);
  536. }
  537. HRESULT __stdcall CMergedEnumPackage::QueryInterface(REFIID riid,
  538. void * * ppObject)
  539. {
  540. *ppObject = NULL; //gd
  541. if ((riid==IID_IUnknown) || (riid==IID_IEnumPackage))
  542. {
  543. *ppObject=(IEnumPackage *) this;
  544. }
  545. else
  546. {
  547. return E_NOINTERFACE;
  548. }
  549. AddRef();
  550. return S_OK;
  551. }
  552. ULONG __stdcall CMergedEnumPackage::AddRef()
  553. {
  554. InterlockedIncrement((long*) &m_dwRefCount);
  555. return m_dwRefCount;
  556. }
  557. ULONG __stdcall CMergedEnumPackage::Release()
  558. {
  559. ULONG dwRefCount;
  560. if ((dwRefCount = InterlockedDecrement((long*) &m_dwRefCount))==0)
  561. {
  562. delete this;
  563. return 0;
  564. }
  565. return dwRefCount;
  566. }
  567. HRESULT __stdcall CMergedEnumPackage::Next(
  568. ULONG celt,
  569. PACKAGEDISPINFO *rgelt,
  570. ULONG *pceltFetched)
  571. {
  572. ULONG count=0, total = 0;
  573. HRESULT hr;
  574. for (; m_csnum < m_cEnum; m_csnum++)
  575. {
  576. count = 0;
  577. hr = m_pcsEnum[m_csnum]->Next(celt, rgelt+total, &count);
  578. if (hr == E_INVALIDARG)
  579. {
  580. return hr;
  581. }
  582. total += count;
  583. celt -= count;
  584. if (!celt)
  585. break;
  586. }
  587. if (pceltFetched)
  588. *pceltFetched = total;
  589. if (!celt)
  590. return S_OK;
  591. return S_FALSE;
  592. }
  593. HRESULT __stdcall CMergedEnumPackage::Skip(
  594. ULONG celt)
  595. {
  596. PACKAGEDISPINFO *pPackageInfo = NULL;
  597. HRESULT hr = S_OK;
  598. ULONG cgot = 0, i;
  599. pPackageInfo = (PACKAGEDISPINFO *)CoTaskMemAlloc(sizeof(PACKAGEDISPINFO)*celt);
  600. if (!pPackageInfo)
  601. return E_OUTOFMEMORY;
  602. hr = Next(celt, pPackageInfo, &cgot);
  603. for (i = 0; i < cgot; i++)
  604. ReleasePackageInfo(pPackageInfo+i);
  605. CoTaskMemFree(pPackageInfo);
  606. return hr;
  607. }
  608. HRESULT __stdcall CMergedEnumPackage::Reset()
  609. {
  610. ULONG i;
  611. for (i = 0; ((i <= m_csnum) && (i < m_cEnum)); i++)
  612. m_pcsEnum[i]->Reset(); // ignoring all error values
  613. m_csnum = 0;
  614. return S_OK;
  615. }
  616. HRESULT __stdcall CMergedEnumPackage::Clone(IEnumPackage **ppIEnumPackage)
  617. {
  618. ULONG i;
  619. CMergedEnumPackage *pClone;
  620. IEnumPackage **pcsEnumCloned=NULL;
  621. pClone = new CMergedEnumPackage;
  622. pcsEnumCloned = (IEnumPackage **)CoTaskMemAlloc(sizeof(IEnumPackage *)*m_cEnum);
  623. if (!pcsEnumCloned)
  624. return E_OUTOFMEMORY;
  625. for ( i = 0; i < m_cEnum; i++)
  626. m_pcsEnum[i]->Clone(&(pcsEnumCloned[i]));
  627. pClone->m_csnum = m_csnum;
  628. pClone->Initialize(pcsEnumCloned, m_cEnum);
  629. *ppIEnumPackage = (IEnumPackage *)pClone;
  630. pClone->AddRef();
  631. CoTaskMemFree(pcsEnumCloned);
  632. return S_OK;
  633. }
  634. HRESULT CMergedEnumPackage::Initialize(IEnumPackage **pcsEnum, ULONG cEnum)
  635. {
  636. ULONG i;
  637. m_csnum = 0;
  638. m_pcsEnum = (IEnumPackage **)CoTaskMemAlloc(sizeof(IEnumPackage *) * cEnum);
  639. if (!m_pcsEnum)
  640. return E_OUTOFMEMORY;
  641. for (i = 0; i < cEnum; i++)
  642. m_pcsEnum[i] = pcsEnum[i];
  643. m_cEnum = cEnum;
  644. return S_OK;
  645. }