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

//+------------------------------------------------------------------------
//
// 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;
}