|
|
//+------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 1997
//
// File: cclsacc.cxx
//
// Contents: Class factory and IUnknown methods for CClassAccess
//
// Author: DebiM
//
//-------------------------------------------------------------------------
#include "cstore.hxx"
HRESULT __stdcall CClassAccess::QueryInterface(REFIID riid, void * * ppvObject)
{ IUnknown *pUnkTemp = NULL; SCODE sc = S_OK; if( IsEqualIID( IID_IUnknown, riid ) ) { pUnkTemp = (IUnknown *)(IClassAccess *)this; } else if( IsEqualIID( IID_IClassAccess, riid ) ) { pUnkTemp = (IUnknown *)(IClassAccess *)this; } else { sc = (E_NOINTERFACE); }
if((pUnkTemp != NULL) && (SUCCEEDED(sc))) { *ppvObject = (void * )pUnkTemp; pUnkTemp->AddRef(); } return(sc);
}
ULONG __stdcall CClassAccess::AddRef() { InterlockedIncrement(( long * )&m_uRefs ); return m_uRefs; }
ULONG __stdcall CClassAccess::Release() { unsigned long uTmp = InterlockedDecrement((long *)&m_uRefs); unsigned long cRef = m_uRefs;
// 0 is the only valid value to check
if (uTmp == 0) { delete this; }
return(cRef); }
//
// Constructor
//
unsigned long gulcClassFactory = 0;
CClassAccessCF::CClassAccessCF() { m_uRefs = 1; InterlockedIncrement((long *) &gulcClassFactory ); }
//
// Destructor
//
CClassAccessCF::~CClassAccessCF() { InterlockedDecrement((long *) &gulcClassFactory ); }
HRESULT __stdcall CClassAccessCF::QueryInterface(REFIID riid, void * * ppvObject) { IUnknown *pUnkTemp = NULL; SCODE sc = S_OK; if( IsEqualIID( IID_IUnknown, riid ) ) { pUnkTemp = (IUnknown *)(ITypeLib *)this; } else if( IsEqualIID( IID_IClassFactory, riid ) ) { pUnkTemp = (IUnknown *)(IClassFactory *)this; } else { sc = (E_NOINTERFACE); }
if((pUnkTemp != NULL) && (SUCCEEDED(sc))) { *ppvObject = (void * )pUnkTemp; pUnkTemp->AddRef(); } return(sc); }
ULONG __stdcall CClassAccessCF::AddRef() { InterlockedIncrement(( long * )&m_uRefs ); return m_uRefs; }
ULONG __stdcall CClassAccessCF::Release() { unsigned long uTmp = InterlockedDecrement((long *)&m_uRefs); unsigned long cRef = m_uRefs;
// 0 is the only valid value to check
if (uTmp == 0) { delete this; }
return(cRef); }
//
// IClassFactory Overide
//
HRESULT __stdcall CClassAccessCF::CreateInstance(IUnknown * pUnkOuter, REFIID riid, void * * ppvObject) { CClassAccess * pIUnk = NULL; SCODE sc = S_OK;
if( pUnkOuter == NULL ) { if( (pIUnk = new CClassAccess()) != NULL) { sc = pIUnk->QueryInterface( riid , ppvObject ); if(FAILED(sc)) { sc = E_UNEXPECTED; } pIUnk->Release(); } else sc = E_OUTOFMEMORY; } else { return E_INVALIDARG; } return (sc); }
HRESULT __stdcall CClassAccessCF::LockServer(BOOL fLock) { if(fLock) { InterlockedIncrement((long *) &gulcClassFactory ); } else { InterlockedDecrement((long *) &gulcClassFactory ); } return(S_OK); }
CClassAccess::CClassAccess()
{ m_uRefs = 1; m_cCalls = 0; pStoreList = NULL; cStores = 0; m_pszClassStorePath = NULL; m_pRsopUserToken = NULL; }
CClassAccess::~CClassAccess()
{ DWORD i;
delete [] m_pszClassStorePath;
for (i = 0; i < cStores; i++) { if (pStoreList[i]->pszClassStorePath) { CsMemFree (pStoreList[i]->pszClassStorePath); pStoreList[i]->pszClassStorePath = NULL; } CsMemFree(pStoreList[i]); pStoreList[i] = NULL;
} CsMemFree(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((DM_WARNING, IDS_CSTORE_CLASSSPEC, TYSPEC_CLSID, szClsid)); }
if (pclsspec->tyspec == TYSPEC_PROGID) {
CSDBGPrint((DM_WARNING, IDS_CSTORE_CLASSSPEC, TYSPEC_PROGID, pclsspec->tagged_union.pProgId)); }
if (pclsspec->tyspec == TYSPEC_FILEEXT) { CSDBGPrint((DM_WARNING, IDS_CSTORE_CLASSSPEC, TYSPEC_FILEEXT, pclsspec->tagged_union.pFileExt)); } }
//----------------------------------------------------------------------
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;
if ((!pPackageInfo)) 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 = LANG_SYSTEM_DEFAULT; QueryContext.dwVersionHi = (DWORD) -1; QueryContext.dwVersionLo = (DWORD) -1; }
if (gDebug) PrintClassSpec(pclsspec);
if (!pStoreList) hr = GetUserClassStores( m_pszClassStorePath, &pStoreList, &cStores, &fCache, &pUserSid);
ERROR_ON_FAILURE(hr);
for (i=0; i < cStores; i++) {
if (!(pICA = GetNextValidClassStore(pStoreList, cStores, pUserSid, NULL, pclsspec, fCache, &i, &hr))) { ASSERT(FAILED(hr)); return hr; }
//
// Call method on this store
//
pICA->AddRef();
hr = pICA->GetAppInfo( pclsspec, &QueryContext, pPackageInfo);
// Release it after use.
pICA->Release();
if ( CS_E_OBJECT_NOTFOUND != hr ) { ERROR_ON_FAILURE(hr); }
//
// 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; }
hr = S_OK; }
if ( ! fFound ) { hr = CS_E_PACKAGE_NOTFOUND; }
Error_Cleanup:
if (pUserSid) CsMemFree (pUserSid);
if ( pICA ) { pICA->Release(); }
if (fFound) { return S_OK; }
return hr; }
#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, PRSOPTOKEN pRsopToken, uCLSSPEC* pClassSpec, BOOL fCache, DWORD * pcount, HRESULT* phr) { IClassAccess *pretICA = NULL; BOOL bSpecificPolicy; LPWSTR wszPolicyGuid;
wszPolicyGuid = NULL;
*phr = S_OK;
bSpecificPolicy = pClassSpec ? TYSPEC_PACKAGENAME == pClassSpec->tyspec : FALSE;
if (bSpecificPolicy) { GuidToString(pClassSpec->tagged_union.ByName.PolicyId, &wszPolicyGuid);
if (!wszPolicyGuid) { *phr = E_OUTOFMEMORY; } }
if (SUCCEEDED(*phr)) { for (pStoreList += (*pcount); (*pcount) < cStores; (*pcount)++, pStoreList++) { if (bSpecificPolicy && !IsClassStoreForPolicy(*pStoreList, wszPolicyGuid)) { continue; }
{ CSDBGPrint((DM_WARNING, IDS_CSTORE_BIND, (*pcount), (*pStoreList)->pszClassStorePath)); //
// Bind to this Class Store
//
if (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;
*phr = pCF->CreateConnectedInstance( NULL, szClassStore, pUserSid, pRsopToken, fCache, (void **)&pCA);
if ( ! SUCCEEDED(*phr) ) { break; }
pretICA = pCA; } else { *phr = CS_E_INVALID_PATH; }
break; } } }
if (wszPolicyGuid) { CsMemFree(wszPolicyGuid); }
if (!pretICA) { ASSERT(FAILED(*phr)); }
CSDBGPrint((DM_WARNING, IDS_CSTORE_BIND_STATUS, *phr));
return pretICA; }
HRESULT STDMETHODCALLTYPE CClassAccess::EnumPackages( LPOLESTR pszPackageName, GUID *pCategory, ULONGLONG *pLastUsn, DWORD dwQuerySpec, IEnumPackage **ppIEnumPackage) { //
// Get the list of Class Stores for this user
//
HRESULT hr = S_OK; ULONG i; IEnumPackage **Enum; ULONG cEnum = 0; CMergedEnumPackage *EnumMerged = NULL; IClassAccess *pICA = NULL; ULONGLONG LastUsn, CopyLastUsn, *pCopyLastUsn; BOOL fCache = FALSE; PSID pUserSid = NULL;
switch ( dwQuerySpec ) { case APPQUERY_ALL: case APPQUERY_ADMINISTRATIVE: case APPQUERY_POLICY: case APPQUERY_USERDISPLAY: case APPQUERY_RSOP_LOGGING: case APPQUERY_RSOP_ARP: break; default: return E_INVALIDARG; }
LastUsn = 0;
if (pLastUsn) { pCopyLastUsn = &CopyLastUsn; *pCopyLastUsn = *pLastUsn; } else pCopyLastUsn = NULL;
//
// Get the list of Class Stores for this user
//
if (!pStoreList) hr = GetUserClassStores( m_pszClassStorePath, &pStoreList, &cStores, &fCache, &pUserSid);
*ppIEnumPackage = NULL;
if ((hr == S_OK) && (cStores == 0)) { hr = CS_E_NO_CLASSSTORE; }
if (SUCCEEDED(hr)) { //
// Dynamically allocate a vector of interfaces (class stores).
// Previously, this was a fixed size array, which, besides
// only allowing for a small number of class stores, caused an
// access violation because the rest of the code assumed that the
// size of the fixed array could be arbitrarily large.
//
Enum = new IEnumPackage*[cStores];
if (!Enum) { hr = E_OUTOFMEMORY; } }
if (!SUCCEEDED(hr)) { //
// Free the Sid
//
if (pUserSid) CsMemFree (pUserSid); return hr; }
for (i=0; i < cStores; i++) { if (!(pICA = GetNextValidClassStore(pStoreList, cStores, pUserSid, m_pRsopUserToken, NULL, fCache, &i, &hr))) { ASSERT(FAILED(hr)); return hr; }
//
// Call method on this store
//
hr = pICA->EnumPackages (pszPackageName, pCategory, pCopyLastUsn, dwQuerySpec, &(Enum[cEnum]));
if (FAILED(hr)) { 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) CsMemFree (pUserSid);
//
// Free the dynamically allocated vector of interfaces
//
delete [] Enum;
if ( pICA ) { pICA->Release(); }
return hr; }
HRESULT __stdcall CClassAccess::SetClassStorePath( LPOLESTR pszClassStorePath, void* pRsopUserToken) { DWORD cchPath;
//
// We only allow this to be set once -- if it's already
// set we return an error.
//
if (m_pszClassStorePath) { return E_INVALIDARG; }
if ( ! pszClassStorePath ) { return S_OK; }
cchPath = lstrlen(pszClassStorePath) + 1;
m_pszClassStorePath = new WCHAR[cchPath];
if (!m_pszClassStorePath) { return E_OUTOFMEMORY; } (void) StringCchCopy(m_pszClassStorePath, cchPath, pszClassStorePath); m_pRsopUserToken = (PRSOPTOKEN) pRsopUserToken;
return S_OK; }
|