|
|
//
// Author: DebiM
// Date: September 1996
//
// File: csacc.cxx
//
// Class Store Manager implementation for a client desktop.
//
// This source file contains implementations for IClassAccess
// interface for CClassAccess object.
// It also contains the IEnumPackage implementation for the
// aggregate of all class containers seen by the caller.
//
//
//---------------------------------------------------------------------
#include "cstore.hxx"
IClassAccess *GetNextValidClassStore(CLASSCONTAINER **pStoreList, DWORD cStores, PSID pUserSid, uCLSSPEC* pClassSpec, BOOL fCache, DWORD* pcount);
extern HRESULT GetUserClassStores( PCLASSCONTAINER **ppStoreList, DWORD *pcStores, BOOL *pfCache, PSID *ppUserSid);
//
// Link list pointer for Class Containers Seen
//
extern CLASSCONTAINER *gpContainerHead;
//
// Link list pointer for User Profiles Seen
//
extern USERPROFILE *gpUserHead;
//
// Global Class Factory for Class Container
//
extern CAppContainerCF *pCF;
//
// Critical Section used during operations on list of class stores
//
extern CRITICAL_SECTION ClassStoreBindList;
//
// CClassAccess implementation
//
CClassAccess::CClassAccess()
{ m_uRefs = 1; m_cCalls = 0; pStoreList = NULL; cStores = 0; }
CClassAccess::~CClassAccess()
{ DWORD i; for (i = 0; i < cStores; i++) { if (pStoreList[i]->gpClassStore) { (pStoreList[i]->gpClassStore)->Release(); pStoreList[i]->gpClassStore = NULL; CSDBGPrint((L"Found open container and closed.")); }
if (pStoreList[i]->pszClassStorePath) { CoTaskMemFree (pStoreList[i]->pszClassStorePath); pStoreList[i]->pszClassStorePath = NULL; } CoTaskMemFree(pStoreList[i]); pStoreList[i] = NULL;
} CoTaskMemFree(pStoreList); cStores = NULL; }
//----------------------------------------------------------------------
//
//
void PrintClassSpec( uCLSSPEC * pclsspec // Class Spec (GUID/Ext/MIME)
) { STRINGGUID szClsid;
if (pclsspec->tyspec == TYSPEC_CLSID) { StringFromGUID (pclsspec->tagged_union.clsid, szClsid); CSDBGPrint((L" ... GetAppInfo by CLSID = %s", szClsid)); }
if (pclsspec->tyspec == TYSPEC_PROGID) { CSDBGPrint((L" ... GetAppInfo by ProgID = %s", pclsspec->tagged_union.pProgId)); }
if (pclsspec->tyspec == TYSPEC_MIMETYPE) { CSDBGPrint((L" ... GetAppInfo by MimeType = %s", pclsspec->tagged_union.pMimeType)); }
if (pclsspec->tyspec == TYSPEC_FILEEXT) { CSDBGPrint((L" ... GetAppInfo by FileExt = %s", pclsspec->tagged_union.pFileExt)); }
if (pclsspec->tyspec == TYSPEC_IID) { StringFromGUID (pclsspec->tagged_union.iid, szClsid); CSDBGPrint((L" ... GetAppInfo by IID = %s", szClsid)); } }
//----------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE CClassAccess::GetAppInfo( uCLSSPEC * pclsspec, // Class Spec (GUID/Ext/MIME)
QUERYCONTEXT * pQryContext, // Query Attributes
PACKAGEDISPINFO * pPackageInfo )
//
// This is the most common method to access the Class Store.
// It queries the class store for implementations for a specific
// Class Id, or File Ext, or ProgID or MIME type.
//
// If a matching implementation is available for the object type,
// client architecture, locale and class context pointer to the
// binary is returned.
{
//
// Assume that this method is called in the security context
// of the user process. Hence there is no need to impersonate.
//
//
// Get the list of Class Stores for this user
//
HRESULT hr = S_OK; ULONG i = 0, j = 0, k= 0; IClassAccess * pICA = NULL; BOOL fCache = FALSE; PSID pUserSid = NULL; BOOL fFound = FALSE; QUERYCONTEXT QueryContext;
// added later.
if (gDebug) { WCHAR Name[32]; DWORD NameSize = 32; if ( ! GetUserName( Name, &NameSize ) ) CSDBGPrint((L"GetAppInfo GetUserName failed 0x%x", GetLastError())); else CSDBGPrint((L"GetAppInfo as %s", Name)); }
if ((!pPackageInfo) || (!IsValidReadPtrIn(pPackageInfo, sizeof(PACKAGEDISPINFO)))) return E_INVALIDARG;
memset(pPackageInfo, 0, sizeof(PACKAGEDISPINFO));
if ( pQryContext ) { QueryContext = *pQryContext; } else { // gets the default information.
QueryContext.dwContext = CLSCTX_ALL; GetDefaultPlatform( &QueryContext.Platform ); QueryContext.Locale = MAKELCID(GetUserDefaultLangID(), SUBLANG_NEUTRAL); QueryContext.dwVersionHi = (DWORD) -1; QueryContext.dwVersionLo = (DWORD) -1; }
if (gDebug) PrintClassSpec(pclsspec);
if (!pStoreList) hr = GetUserClassStores( &pStoreList, &cStores, &fCache, &pUserSid);
ERROR_ON_FAILURE(hr);
for (i=0; i < cStores; i++) {
if (!(pICA = GetNextValidClassStore(pStoreList, cStores, pUserSid, pclsspec, fCache, &i))) continue;
//
// Call method on this store
//
pICA->AddRef();
hr = pICA->GetAppInfo( pclsspec, &QueryContext, pPackageInfo);
// Release it after use.
pICA->Release();
//
// Special case error return E_INVALIDARG
// Do not continue to look, return this.
//
if (hr == E_INVALIDARG) { ERROR_ON_FAILURE(hr); }
//
// maintain access counters
//
(pStoreList[i])->cAccess++;
//
// We are iterating through the class stores from highest precedence to lowest --
// thus, the first container to return success will be our choice.
//
if (SUCCEEDED(hr)) { fFound = TRUE; break; } else { (pStoreList[i])->cNotFound++; CSDBGPrint((L"CClassAccess::GetAppInfo() returned 0x%x", hr)); } hr = S_OK; }
Error_Cleanup: if (pUserSid) CoTaskMemFree (pUserSid); if (fFound) { CSDBGPrint((L"Returning Package %s", pPackageInfo->pszPackageName)); return S_OK; } if (!SUCCEEDED(hr)) return hr; return CS_E_PACKAGE_NOTFOUND; }
#define MAX_GUID_CCH 38
//
// IsClassStoreForPolicy
//
BOOL IsClassStoreForPolicy(CLASSCONTAINER* pClassStore, LPWSTR wszPolicyId) { LPWSTR pszPolicyGuid;
// Path looks like:
// LDAP://CN=<Class Store Name>,CN=<user-or-machine>,CN=<{policy-guid}>,...
//
// Look for ',' first
//
pszPolicyGuid = wcschr(pClassStore->pszClassStorePath, L',');
if (!pszPolicyGuid) { return FALSE; }
//
// Look for the second ','
//
pszPolicyGuid = wcschr(pszPolicyGuid + 1, L',');
if (!pszPolicyGuid) { return FALSE; }
//
// Now get to '{' at start of guid -- it is 4 chars
// past the ',' which we are currently at. Use wcschr
// to make sure we don't go past the end of the string
// and that our assumptions about the structure of the
// path are correct
//
if (wcschr(pszPolicyGuid, L'{') == (pszPolicyGuid + 4)) {
pszPolicyGuid += 4;
//
// Now that we have the '{', we are at the start of the guid
// and can compare with the requested policy id
//
if (_wcsnicmp(pszPolicyGuid, wszPolicyId, MAX_GUID_CCH) == 0) { return TRUE; } }
return FALSE; }
//
// GetNextValidClassStore
//
//
IClassAccess *GetNextValidClassStore(CLASSCONTAINER** pStoreList, DWORD cStores, PSID pUserSid, uCLSSPEC* pClassSpec, BOOL fCache, DWORD * pcount) { IClassAccess *pretICA = NULL; BOOL bSpecificPolicy; LPWSTR wszPolicyGuid; HRESULT hr;
wszPolicyGuid = NULL;
hr = S_OK;
bSpecificPolicy = pClassSpec ? TYSPEC_PACKAGENAME == pClassSpec->tyspec : FALSE;
if (bSpecificPolicy) { hr = StringFromCLSID(pClassSpec->tagged_union.ByName.PolicyId, &wszPolicyGuid); }
if (SUCCEEDED(hr)) { for (pStoreList += (*pcount); (*pcount) < cStores; (*pcount)++, pStoreList++) { if ((*pStoreList)->gpClassStore != NULL) { break; }
if (bSpecificPolicy && !IsClassStoreForPolicy(*pStoreList, wszPolicyGuid)) { continue; }
if (FALSE) // ((*pStoreList)->cBindFailures >= MAX_BIND_ATTEMPTS)
{ // Number of continuous failures have reached MAX_BIND_ATTEMPTS
// for this container.
// Will temporarily disable lookups in this container.
// Report it in EventLog once
//
if ((*pStoreList)->cBindFailures == MAX_BIND_ATTEMPTS) { //LogCsPathError((*pStoreList)->pszClassStorePath, hr);
(*pStoreList)->cBindFailures++; } continue; } else { CSDBGPrint((L"CS: .. Connecting to Store %d ... %s..", (*pcount), (*pStoreList)->pszClassStorePath)); //
// Bind to this Class Store
//
if ((wcsncmp ((*pStoreList)->pszClassStorePath, L"ADCS:", 5) == 0) || (wcsncmp ((*pStoreList)->pszClassStorePath, L"LDAP:", 5) == 0)) { //
// If the Storename starts with ADCS or LDAP
// it is NTDS based implementation. Call directly.
//
IClassAccess *pCA = NULL; LPOLESTR szClassStore = (*pStoreList)->pszClassStorePath;
// skipping ADCS:
if (wcsncmp ((*pStoreList)->pszClassStorePath, L"ADCS:", 5) == 0) szClassStore += 5;
hr = pCF->CreateConnectedInstance( szClassStore, pUserSid, fCache, (void **)&pCA);
if (SUCCEEDED(hr)) { EnterCriticalSection (&ClassStoreBindList); if ((*pStoreList)->gpClassStore != NULL) { pCA->Release(); pCA = NULL; } else { (*pStoreList)->gpClassStore = pCA; pCA = NULL; } LeaveCriticalSection (&ClassStoreBindList); } } else { //
// Support for Third Party Pluggable
// Class Stores is not in Beta2.
//
ReportEventCS(hr = CS_E_INVALID_PATH, CS_E_INVALID_PATH, (*pStoreList)->pszClassStorePath); }
if (SUCCEEDED(hr)) { (*pStoreList)->cBindFailures = 0; hr = S_OK; break; }
if (!SUCCEEDED(hr)) { CSDBGPrint((L"Failed to connect to this store")); if ((*pStoreList)->cBindFailures == 0) { // First failue or First failure after successful
// binding.
// Report it in EventLog
//
//LogCsPathError((*pStoreList)->pszClassStorePath, hr);
} ((*pStoreList)->cBindFailures) ++; continue; } } } }
if (wszPolicyGuid) { CoTaskMemFree(wszPolicyGuid); }
if ((*pcount) != cStores) pretICA = (*pStoreList)->gpClassStore;
return pretICA; }
HRESULT STDMETHODCALLTYPE CClassAccess::EnumPackages( LPOLESTR pszPackageName, GUID *pCategory, ULONGLONG *pLastUsn, DWORD dwAppFlags, // AppType options
IEnumPackage **ppIEnumPackage) { //
// Get the list of Class Stores for this user
//
HRESULT hr = S_OK; ULONG i; IEnumPackage *Enum[MAXCLASSSTORES]; ULONG cEnum = 0; CMergedEnumPackage *EnumMerged = NULL; IClassAccess *pICA = NULL; ULONGLONG LastUsn, CopyLastUsn, *pCopyLastUsn; BOOL fCache = FALSE; PSID pUserSid = NULL;
// added later.
if (gDebug) { WCHAR Name[32]; DWORD NameSize = 32; if ( ! GetUserName( Name, &NameSize ) ) CSDBGPrint((L"EnumPackage GetUserName failed 0x%x", GetLastError())); else CSDBGPrint((L"EnumPackage as %s", Name)); }
LastUsn = 0;
if (pLastUsn) { //
// Check pLastUsn
//
if (!IsValidReadPtrIn(pLastUsn, sizeof(ULONGLONG))) return E_INVALIDARG;
pCopyLastUsn = &CopyLastUsn; *pCopyLastUsn = *pLastUsn; } else pCopyLastUsn = NULL; //
// Get the list of Class Stores for this user
//
if (!pStoreList) hr = GetUserClassStores( &pStoreList, &cStores, &fCache, &pUserSid);
*ppIEnumPackage = NULL;
if ((hr == S_OK) && (cStores == 0)) { hr = CS_E_NO_CLASSSTORE; }
if (!SUCCEEDED(hr)) { //
// Free the Sid
//
if (pUserSid) CoTaskMemFree (pUserSid); return hr; }
for (i=0; i < cStores; i++) { if (!(pICA = GetNextValidClassStore(pStoreList, cStores, pUserSid, NULL, fCache, &i))) continue; //
// Call method on this store
//
hr = pICA->EnumPackages (pszPackageName, pCategory, pCopyLastUsn, dwAppFlags, &(Enum[cEnum]));
if (hr == E_INVALIDARG) { break; }
if (pCopyLastUsn) { if (LastUsn < *pCopyLastUsn) LastUsn = *pCopyLastUsn; *pCopyLastUsn = *pLastUsn; } if (SUCCEEDED(hr)) cEnum++; } if (SUCCEEDED(hr)) { EnumMerged = new CMergedEnumPackage; hr = EnumMerged->Initialize(Enum, cEnum); if (FAILED(hr)) { for (i = 0; i < cEnum; i++) Enum[i]->Release(); delete EnumMerged; } else { hr = EnumMerged->QueryInterface(IID_IEnumPackage, (void **)ppIEnumPackage); if (FAILED(hr)) delete EnumMerged; } if (pLastUsn) { if (LastUsn > *pLastUsn) *pLastUsn = LastUsn; } }
if (pUserSid) CoTaskMemFree (pUserSid); return hr; }
//--------------------------------------------------------------
CMergedEnumPackage::CMergedEnumPackage() { m_pcsEnum = NULL; m_cEnum = 0; m_csnum = 0; m_dwRefCount = 0; }
CMergedEnumPackage::~CMergedEnumPackage() { ULONG i; for (i = 0; i < m_cEnum; i++) m_pcsEnum[i]->Release(); CoTaskMemFree(m_pcsEnum); }
HRESULT __stdcall CMergedEnumPackage::QueryInterface(REFIID riid, void * * ppObject) { *ppObject = NULL; //gd
if ((riid==IID_IUnknown) || (riid==IID_IEnumPackage)) { *ppObject=(IEnumPackage *) this; } else { return E_NOINTERFACE; } AddRef(); return S_OK; }
ULONG __stdcall CMergedEnumPackage::AddRef() { InterlockedIncrement((long*) &m_dwRefCount); return m_dwRefCount; }
ULONG __stdcall CMergedEnumPackage::Release() { ULONG dwRefCount; if ((dwRefCount = InterlockedDecrement((long*) &m_dwRefCount))==0) { delete this; return 0; } return dwRefCount; }
HRESULT __stdcall CMergedEnumPackage::Next( ULONG celt, PACKAGEDISPINFO *rgelt, ULONG *pceltFetched) { ULONG count=0, total = 0; HRESULT hr;
for (; m_csnum < m_cEnum; m_csnum++) { count = 0; hr = m_pcsEnum[m_csnum]->Next(celt, rgelt+total, &count);
if (hr == E_INVALIDARG) { return hr; }
total += count; celt -= count;
if (!celt) break; } if (pceltFetched) *pceltFetched = total; if (!celt) return S_OK; return S_FALSE; }
HRESULT __stdcall CMergedEnumPackage::Skip( ULONG celt) { PACKAGEDISPINFO *pPackageInfo = NULL; HRESULT hr = S_OK; ULONG cgot = 0, i;
pPackageInfo = (PACKAGEDISPINFO *)CoTaskMemAlloc(sizeof(PACKAGEDISPINFO)*celt); if (!pPackageInfo) return E_OUTOFMEMORY;
hr = Next(celt, pPackageInfo, &cgot);
for (i = 0; i < cgot; i++) ReleasePackageInfo(pPackageInfo+i); CoTaskMemFree(pPackageInfo); return hr; }
HRESULT __stdcall CMergedEnumPackage::Reset() { ULONG i; for (i = 0; ((i <= m_csnum) && (i < m_cEnum)); i++) m_pcsEnum[i]->Reset(); // ignoring all error values
m_csnum = 0; return S_OK; }
HRESULT __stdcall CMergedEnumPackage::Clone(IEnumPackage **ppIEnumPackage) { ULONG i; CMergedEnumPackage *pClone; IEnumPackage **pcsEnumCloned=NULL;
pClone = new CMergedEnumPackage; pcsEnumCloned = (IEnumPackage **)CoTaskMemAlloc(sizeof(IEnumPackage *)*m_cEnum); if (!pcsEnumCloned) return E_OUTOFMEMORY;
for ( i = 0; i < m_cEnum; i++) m_pcsEnum[i]->Clone(&(pcsEnumCloned[i]));
pClone->m_csnum = m_csnum; pClone->Initialize(pcsEnumCloned, m_cEnum); *ppIEnumPackage = (IEnumPackage *)pClone; pClone->AddRef(); CoTaskMemFree(pcsEnumCloned); return S_OK; }
HRESULT CMergedEnumPackage::Initialize(IEnumPackage **pcsEnum, ULONG cEnum) { ULONG i; m_csnum = 0; m_pcsEnum = (IEnumPackage **)CoTaskMemAlloc(sizeof(IEnumPackage *) * cEnum); if (!m_pcsEnum) return E_OUTOFMEMORY; for (i = 0; i < cEnum; i++) m_pcsEnum[i] = pcsEnum[i]; m_cEnum = cEnum; return S_OK; }
|