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.

743 lines
17 KiB

  1. //+------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 1997
  5. //
  6. // File: cclsacc.cxx
  7. //
  8. // Contents: Class factory and IUnknown methods for CClassAccess
  9. //
  10. // Author: DebiM
  11. //
  12. //-------------------------------------------------------------------------
  13. #include "cstore.hxx"
  14. HRESULT __stdcall CClassAccess::QueryInterface(REFIID riid, void * * ppvObject)
  15. {
  16. IUnknown *pUnkTemp = NULL;
  17. SCODE sc = S_OK;
  18. if( IsEqualIID( IID_IUnknown, riid ) )
  19. {
  20. pUnkTemp = (IUnknown *)(IClassAccess *)this;
  21. }
  22. else if( IsEqualIID( IID_IClassAccess, riid ) )
  23. {
  24. pUnkTemp = (IUnknown *)(IClassAccess *)this;
  25. }
  26. else
  27. {
  28. sc = (E_NOINTERFACE);
  29. }
  30. if((pUnkTemp != NULL) && (SUCCEEDED(sc)))
  31. {
  32. *ppvObject = (void * )pUnkTemp;
  33. pUnkTemp->AddRef();
  34. }
  35. return(sc);
  36. }
  37. ULONG __stdcall CClassAccess::AddRef()
  38. {
  39. InterlockedIncrement(( long * )&m_uRefs );
  40. return m_uRefs;
  41. }
  42. ULONG __stdcall CClassAccess::Release()
  43. {
  44. unsigned long uTmp = InterlockedDecrement((long *)&m_uRefs);
  45. unsigned long cRef = m_uRefs;
  46. // 0 is the only valid value to check
  47. if (uTmp == 0)
  48. {
  49. delete this;
  50. }
  51. return(cRef);
  52. }
  53. //
  54. // Constructor
  55. //
  56. unsigned long gulcClassFactory = 0;
  57. CClassAccessCF::CClassAccessCF()
  58. {
  59. m_uRefs = 1;
  60. InterlockedIncrement((long *) &gulcClassFactory );
  61. }
  62. //
  63. // Destructor
  64. //
  65. CClassAccessCF::~CClassAccessCF()
  66. {
  67. InterlockedDecrement((long *) &gulcClassFactory );
  68. }
  69. HRESULT __stdcall CClassAccessCF::QueryInterface(REFIID riid, void * * ppvObject)
  70. {
  71. IUnknown *pUnkTemp = NULL;
  72. SCODE sc = S_OK;
  73. if( IsEqualIID( IID_IUnknown, riid ) )
  74. {
  75. pUnkTemp = (IUnknown *)(ITypeLib *)this;
  76. }
  77. else if( IsEqualIID( IID_IClassFactory, riid ) )
  78. {
  79. pUnkTemp = (IUnknown *)(IClassFactory *)this;
  80. }
  81. else
  82. {
  83. sc = (E_NOINTERFACE);
  84. }
  85. if((pUnkTemp != NULL) && (SUCCEEDED(sc)))
  86. {
  87. *ppvObject = (void * )pUnkTemp;
  88. pUnkTemp->AddRef();
  89. }
  90. return(sc);
  91. }
  92. ULONG __stdcall CClassAccessCF::AddRef()
  93. {
  94. InterlockedIncrement(( long * )&m_uRefs );
  95. return m_uRefs;
  96. }
  97. ULONG __stdcall CClassAccessCF::Release()
  98. {
  99. unsigned long uTmp = InterlockedDecrement((long *)&m_uRefs);
  100. unsigned long cRef = m_uRefs;
  101. // 0 is the only valid value to check
  102. if (uTmp == 0)
  103. {
  104. delete this;
  105. }
  106. return(cRef);
  107. }
  108. //
  109. // IClassFactory Overide
  110. //
  111. HRESULT __stdcall CClassAccessCF::CreateInstance(IUnknown * pUnkOuter, REFIID riid, void * * ppvObject)
  112. {
  113. CClassAccess * pIUnk = NULL;
  114. SCODE sc = S_OK;
  115. if( pUnkOuter == NULL )
  116. {
  117. if( (pIUnk = new CClassAccess()) != NULL)
  118. {
  119. sc = pIUnk->QueryInterface( riid , ppvObject );
  120. if(FAILED(sc))
  121. {
  122. sc = E_UNEXPECTED;
  123. }
  124. pIUnk->Release();
  125. }
  126. else
  127. sc = E_OUTOFMEMORY;
  128. }
  129. else
  130. {
  131. return E_INVALIDARG;
  132. }
  133. return (sc);
  134. }
  135. HRESULT __stdcall CClassAccessCF::LockServer(BOOL fLock)
  136. {
  137. if(fLock)
  138. { InterlockedIncrement((long *) &gulcClassFactory ); }
  139. else
  140. { InterlockedDecrement((long *) &gulcClassFactory ); }
  141. return(S_OK);
  142. }
  143. CClassAccess::CClassAccess()
  144. {
  145. m_uRefs = 1;
  146. m_cCalls = 0;
  147. pStoreList = NULL;
  148. cStores = 0;
  149. m_pszClassStorePath = NULL;
  150. m_pRsopUserToken = NULL;
  151. }
  152. CClassAccess::~CClassAccess()
  153. {
  154. DWORD i;
  155. delete [] m_pszClassStorePath;
  156. for (i = 0; i < cStores; i++)
  157. {
  158. if (pStoreList[i]->pszClassStorePath)
  159. {
  160. CsMemFree (pStoreList[i]->pszClassStorePath);
  161. pStoreList[i]->pszClassStorePath = NULL;
  162. }
  163. CsMemFree(pStoreList[i]);
  164. pStoreList[i] = NULL;
  165. }
  166. CsMemFree(pStoreList);
  167. cStores = NULL;
  168. }
  169. //----------------------------------------------------------------------
  170. //
  171. //
  172. void PrintClassSpec(
  173. uCLSSPEC * pclsspec // Class Spec (GUID/Ext/MIME)
  174. )
  175. {
  176. STRINGGUID szClsid;
  177. if (pclsspec->tyspec == TYSPEC_CLSID)
  178. {
  179. StringFromGUID (pclsspec->tagged_union.clsid, szClsid);
  180. CSDBGPrint((DM_WARNING,
  181. IDS_CSTORE_CLASSSPEC,
  182. TYSPEC_CLSID,
  183. szClsid));
  184. }
  185. if (pclsspec->tyspec == TYSPEC_PROGID)
  186. {
  187. CSDBGPrint((DM_WARNING,
  188. IDS_CSTORE_CLASSSPEC,
  189. TYSPEC_PROGID,
  190. pclsspec->tagged_union.pProgId));
  191. }
  192. if (pclsspec->tyspec == TYSPEC_FILEEXT)
  193. {
  194. CSDBGPrint((DM_WARNING,
  195. IDS_CSTORE_CLASSSPEC,
  196. TYSPEC_FILEEXT,
  197. pclsspec->tagged_union.pFileExt));
  198. }
  199. }
  200. //----------------------------------------------------------------------
  201. HRESULT STDMETHODCALLTYPE
  202. CClassAccess::GetAppInfo(
  203. uCLSSPEC * pclsspec, // Class Spec (GUID/Ext/MIME)
  204. QUERYCONTEXT * pQryContext, // Query Attributes
  205. PACKAGEDISPINFO * pPackageInfo
  206. )
  207. //
  208. // This is the most common method to access the Class Store.
  209. // It queries the class store for implementations for a specific
  210. // Class Id, or File Ext, or ProgID or MIME type.
  211. //
  212. // If a matching implementation is available for the object type,
  213. // client architecture, locale and class context pointer to the
  214. // binary is returned.
  215. {
  216. //
  217. // Assume that this method is called in the security context
  218. // of the user process. Hence there is no need to impersonate.
  219. //
  220. //
  221. // Get the list of Class Stores for this user
  222. //
  223. HRESULT hr = S_OK;
  224. ULONG i = 0, j = 0, k= 0;
  225. IClassAccess * pICA = NULL;
  226. BOOL fCache = FALSE;
  227. PSID pUserSid = NULL;
  228. BOOL fFound = FALSE;
  229. QUERYCONTEXT QueryContext;
  230. if ((!pPackageInfo))
  231. return E_INVALIDARG;
  232. memset(pPackageInfo, 0, sizeof(PACKAGEDISPINFO));
  233. if ( pQryContext )
  234. {
  235. QueryContext = *pQryContext;
  236. }
  237. else
  238. {
  239. // gets the default information.
  240. QueryContext.dwContext = CLSCTX_ALL;
  241. GetDefaultPlatform( &QueryContext.Platform );
  242. QueryContext.Locale = LANG_SYSTEM_DEFAULT;
  243. QueryContext.dwVersionHi = (DWORD) -1;
  244. QueryContext.dwVersionLo = (DWORD) -1;
  245. }
  246. if (gDebug)
  247. PrintClassSpec(pclsspec);
  248. if (!pStoreList)
  249. hr = GetUserClassStores(
  250. m_pszClassStorePath,
  251. &pStoreList,
  252. &cStores,
  253. &fCache,
  254. &pUserSid);
  255. ERROR_ON_FAILURE(hr);
  256. for (i=0; i < cStores; i++)
  257. {
  258. if (!(pICA = GetNextValidClassStore(pStoreList, cStores, pUserSid, NULL, pclsspec, fCache, &i, &hr)))
  259. {
  260. ASSERT(FAILED(hr));
  261. return hr;
  262. }
  263. //
  264. // Call method on this store
  265. //
  266. pICA->AddRef();
  267. hr = pICA->GetAppInfo(
  268. pclsspec,
  269. &QueryContext,
  270. pPackageInfo);
  271. // Release it after use.
  272. pICA->Release();
  273. if ( CS_E_OBJECT_NOTFOUND != hr )
  274. {
  275. ERROR_ON_FAILURE(hr);
  276. }
  277. //
  278. // We are iterating through the class stores from highest precedence to lowest --
  279. // thus, the first container to return success will be our choice.
  280. //
  281. if (SUCCEEDED(hr))
  282. {
  283. fFound = TRUE;
  284. break;
  285. }
  286. hr = S_OK;
  287. }
  288. if ( ! fFound )
  289. {
  290. hr = CS_E_PACKAGE_NOTFOUND;
  291. }
  292. Error_Cleanup:
  293. if (pUserSid)
  294. CsMemFree (pUserSid);
  295. if ( pICA )
  296. {
  297. pICA->Release();
  298. }
  299. if (fFound)
  300. {
  301. return S_OK;
  302. }
  303. return hr;
  304. }
  305. #define MAX_GUID_CCH 38
  306. //
  307. // IsClassStoreForPolicy
  308. //
  309. BOOL IsClassStoreForPolicy(CLASSCONTAINER* pClassStore,
  310. LPWSTR wszPolicyId)
  311. {
  312. LPWSTR pszPolicyGuid;
  313. // Path looks like:
  314. // LDAP://CN=<Class Store Name>,CN=<user-or-machine>,CN=<{policy-guid}>,...
  315. //
  316. // Look for ',' first
  317. //
  318. pszPolicyGuid = wcschr(pClassStore->pszClassStorePath, L',');
  319. if (!pszPolicyGuid)
  320. {
  321. return FALSE;
  322. }
  323. //
  324. // Look for the second ','
  325. //
  326. pszPolicyGuid = wcschr(pszPolicyGuid + 1, L',');
  327. if (!pszPolicyGuid)
  328. {
  329. return FALSE;
  330. }
  331. //
  332. // Now get to '{' at start of guid -- it is 4 chars
  333. // past the ',' which we are currently at. Use wcschr
  334. // to make sure we don't go past the end of the string
  335. // and that our assumptions about the structure of the
  336. // path are correct
  337. //
  338. if (wcschr(pszPolicyGuid, L'{') == (pszPolicyGuid + 4))
  339. {
  340. pszPolicyGuid += 4;
  341. //
  342. // Now that we have the '{', we are at the start of the guid
  343. // and can compare with the requested policy id
  344. //
  345. if (_wcsnicmp(pszPolicyGuid, wszPolicyId, MAX_GUID_CCH) == 0)
  346. {
  347. return TRUE;
  348. }
  349. }
  350. return FALSE;
  351. }
  352. //
  353. // GetNextValidClassStore
  354. //
  355. //
  356. IClassAccess *GetNextValidClassStore(CLASSCONTAINER** pStoreList,
  357. DWORD cStores,
  358. PSID pUserSid,
  359. PRSOPTOKEN pRsopToken,
  360. uCLSSPEC* pClassSpec,
  361. BOOL fCache,
  362. DWORD * pcount,
  363. HRESULT* phr)
  364. {
  365. IClassAccess *pretICA = NULL;
  366. BOOL bSpecificPolicy;
  367. LPWSTR wszPolicyGuid;
  368. wszPolicyGuid = NULL;
  369. *phr = S_OK;
  370. bSpecificPolicy = pClassSpec ? TYSPEC_PACKAGENAME == pClassSpec->tyspec : FALSE;
  371. if (bSpecificPolicy)
  372. {
  373. GuidToString(pClassSpec->tagged_union.ByName.PolicyId, &wszPolicyGuid);
  374. if (!wszPolicyGuid) {
  375. *phr = E_OUTOFMEMORY;
  376. }
  377. }
  378. if (SUCCEEDED(*phr))
  379. {
  380. for (pStoreList += (*pcount); (*pcount) < cStores; (*pcount)++, pStoreList++)
  381. {
  382. if (bSpecificPolicy &&
  383. !IsClassStoreForPolicy(*pStoreList, wszPolicyGuid))
  384. {
  385. continue;
  386. }
  387. {
  388. CSDBGPrint((DM_WARNING,
  389. IDS_CSTORE_BIND,
  390. (*pcount),
  391. (*pStoreList)->pszClassStorePath));
  392. //
  393. // Bind to this Class Store
  394. //
  395. if (wcsncmp((*pStoreList)->pszClassStorePath, L"LDAP:", 5) == 0)
  396. {
  397. //
  398. // If the Storename starts with ADCS or LDAP
  399. // it is NTDS based implementation. Call directly.
  400. //
  401. IClassAccess *pCA = NULL;
  402. LPOLESTR szClassStore = (*pStoreList)->pszClassStorePath;
  403. *phr = pCF->CreateConnectedInstance(
  404. NULL,
  405. szClassStore,
  406. pUserSid,
  407. pRsopToken,
  408. fCache,
  409. (void **)&pCA);
  410. if ( ! SUCCEEDED(*phr) )
  411. {
  412. break;
  413. }
  414. pretICA = pCA;
  415. }
  416. else
  417. {
  418. *phr = CS_E_INVALID_PATH;
  419. }
  420. break;
  421. }
  422. }
  423. }
  424. if (wszPolicyGuid)
  425. {
  426. CsMemFree(wszPolicyGuid);
  427. }
  428. if (!pretICA)
  429. {
  430. ASSERT(FAILED(*phr));
  431. }
  432. CSDBGPrint((DM_WARNING,
  433. IDS_CSTORE_BIND_STATUS,
  434. *phr));
  435. return pretICA;
  436. }
  437. HRESULT STDMETHODCALLTYPE CClassAccess::EnumPackages(
  438. LPOLESTR pszPackageName,
  439. GUID *pCategory,
  440. ULONGLONG *pLastUsn,
  441. DWORD dwQuerySpec,
  442. IEnumPackage **ppIEnumPackage)
  443. {
  444. //
  445. // Get the list of Class Stores for this user
  446. //
  447. HRESULT hr = S_OK;
  448. ULONG i;
  449. IEnumPackage **Enum;
  450. ULONG cEnum = 0;
  451. CMergedEnumPackage *EnumMerged = NULL;
  452. IClassAccess *pICA = NULL;
  453. ULONGLONG LastUsn, CopyLastUsn, *pCopyLastUsn;
  454. BOOL fCache = FALSE;
  455. PSID pUserSid = NULL;
  456. switch ( dwQuerySpec )
  457. {
  458. case APPQUERY_ALL:
  459. case APPQUERY_ADMINISTRATIVE:
  460. case APPQUERY_POLICY:
  461. case APPQUERY_USERDISPLAY:
  462. case APPQUERY_RSOP_LOGGING:
  463. case APPQUERY_RSOP_ARP:
  464. break;
  465. default:
  466. return E_INVALIDARG;
  467. }
  468. LastUsn = 0;
  469. if (pLastUsn)
  470. {
  471. pCopyLastUsn = &CopyLastUsn;
  472. *pCopyLastUsn = *pLastUsn;
  473. }
  474. else
  475. pCopyLastUsn = NULL;
  476. //
  477. // Get the list of Class Stores for this user
  478. //
  479. if (!pStoreList)
  480. hr = GetUserClassStores(
  481. m_pszClassStorePath,
  482. &pStoreList,
  483. &cStores,
  484. &fCache,
  485. &pUserSid);
  486. *ppIEnumPackage = NULL;
  487. if ((hr == S_OK) && (cStores == 0))
  488. {
  489. hr = CS_E_NO_CLASSSTORE;
  490. }
  491. if (SUCCEEDED(hr))
  492. {
  493. //
  494. // Dynamically allocate a vector of interfaces (class stores).
  495. // Previously, this was a fixed size array, which, besides
  496. // only allowing for a small number of class stores, caused an
  497. // access violation because the rest of the code assumed that the
  498. // size of the fixed array could be arbitrarily large.
  499. //
  500. Enum = new IEnumPackage*[cStores];
  501. if (!Enum)
  502. {
  503. hr = E_OUTOFMEMORY;
  504. }
  505. }
  506. if (!SUCCEEDED(hr))
  507. {
  508. //
  509. // Free the Sid
  510. //
  511. if (pUserSid)
  512. CsMemFree (pUserSid);
  513. return hr;
  514. }
  515. for (i=0; i < cStores; i++)
  516. {
  517. if (!(pICA = GetNextValidClassStore(pStoreList, cStores, pUserSid, m_pRsopUserToken, NULL, fCache, &i, &hr)))
  518. {
  519. ASSERT(FAILED(hr));
  520. return hr;
  521. }
  522. //
  523. // Call method on this store
  524. //
  525. hr = pICA->EnumPackages (pszPackageName,
  526. pCategory,
  527. pCopyLastUsn,
  528. dwQuerySpec,
  529. &(Enum[cEnum]));
  530. if (FAILED(hr))
  531. {
  532. break;
  533. }
  534. if (pCopyLastUsn)
  535. {
  536. if (LastUsn < *pCopyLastUsn)
  537. LastUsn = *pCopyLastUsn;
  538. *pCopyLastUsn = *pLastUsn;
  539. }
  540. if (SUCCEEDED(hr))
  541. cEnum++;
  542. }
  543. if (SUCCEEDED(hr))
  544. {
  545. EnumMerged = new CMergedEnumPackage;
  546. hr = EnumMerged->Initialize(Enum, cEnum);
  547. if (FAILED(hr))
  548. {
  549. for (i = 0; i < cEnum; i++)
  550. Enum[i]->Release();
  551. delete EnumMerged;
  552. }
  553. else
  554. {
  555. hr = EnumMerged->QueryInterface(IID_IEnumPackage, (void **)ppIEnumPackage);
  556. if (FAILED(hr))
  557. delete EnumMerged;
  558. }
  559. if (pLastUsn)
  560. {
  561. if (LastUsn > *pLastUsn)
  562. *pLastUsn = LastUsn;
  563. }
  564. }
  565. if (pUserSid)
  566. CsMemFree (pUserSid);
  567. //
  568. // Free the dynamically allocated vector of interfaces
  569. //
  570. delete [] Enum;
  571. if ( pICA )
  572. {
  573. pICA->Release();
  574. }
  575. return hr;
  576. }
  577. HRESULT __stdcall CClassAccess::SetClassStorePath(
  578. LPOLESTR pszClassStorePath,
  579. void* pRsopUserToken)
  580. {
  581. DWORD cchPath;
  582. //
  583. // We only allow this to be set once -- if it's already
  584. // set we return an error.
  585. //
  586. if (m_pszClassStorePath)
  587. {
  588. return E_INVALIDARG;
  589. }
  590. if ( ! pszClassStorePath )
  591. {
  592. return S_OK;
  593. }
  594. cchPath = lstrlen(pszClassStorePath) + 1;
  595. m_pszClassStorePath = new WCHAR[cchPath];
  596. if (!m_pszClassStorePath)
  597. {
  598. return E_OUTOFMEMORY;
  599. }
  600. (void) StringCchCopy(m_pszClassStorePath, cchPath, pszClassStorePath);
  601. m_pRsopUserToken = (PRSOPTOKEN) pRsopUserToken;
  602. return S_OK;
  603. }
  604.