|
|
//
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 1999
//
// Author: DebiM
// Date: January 97
// Revision History:
// Made Changes for reimplementation with adsldpc interfaces.
// UShaji, Mar 1998
//
// Class Access Implementation
//
// This source file contains implementations for IClassAccess
// interface on CAppContainer object.
//
// It uses ADs interfaces (over LDAP) to talk to an LDAP
// provider such as NTDS.
//
//---------------------------------------------------------------------
//
#include "cstore.hxx"
CBindingList BindingCache;
//
// Critical Section for All Global Objects.
//
extern CRITICAL_SECTION ClassStoreBindList;
HRESULT UsnGet(ADS_ATTR_INFO Attr, CSUSN *pUsn);
long CompareUsn(CSUSN *pUsn1, CSUSN *pUsn2) { return CompareFileTime((FILETIME *)pUsn1, (FILETIME *)pUsn2); }
void GetExpiredTime( FILETIME* pftCurrentTime, FILETIME* pftExpiredTime ) { //
// Add the cache interval time to determine
// the time this will expire
//
LARGE_INTEGER liTime;
//
// First copy the filetime to a large integer so
// we can perform arithmetic
//
liTime.LowPart = pftCurrentTime->dwLowDateTime; liTime.HighPart = pftCurrentTime->dwHighDateTime;
//
// The compiler can perform 64 bit math -- use this
// to perform the arithmetic for calculating the
// time at which cache entries will expire
//
liTime.QuadPart += CACHE_PURGE_TIME_FILETIME_INTERVAL;
//
// Now copy the information back to the caller's structure
//
pftExpiredTime->dwLowDateTime = liTime.LowPart; pftExpiredTime->dwHighDateTime = liTime.HighPart; }
BOOL IsExpired( FILETIME* pftCurrentTime, FILETIME* pftExpiredTime) { SYSTEMTIME SystemTimeCurrent; SYSTEMTIME SystemTimeExpiration; BOOL bRetrievedTime;
bRetrievedTime = FileTimeToSystemTime( pftCurrentTime, &SystemTimeCurrent);
bRetrievedTime &= FileTimeToSystemTime( pftExpiredTime, &SystemTimeExpiration);
if ( bRetrievedTime ) { CSDBGPrint(( DM_VERBOSE, IDS_CSTORE_CACHE_EXPIRE, L"Current Time", SystemTimeCurrent.wMonth, SystemTimeCurrent.wDay, SystemTimeCurrent.wYear, SystemTimeCurrent.wHour, SystemTimeCurrent.wMinute, SystemTimeCurrent.wSecond));
CSDBGPrint(( DM_VERBOSE, IDS_CSTORE_CACHE_EXPIRE, L"Expire Time", SystemTimeExpiration.wMonth, SystemTimeExpiration.wDay, SystemTimeExpiration.wYear, SystemTimeExpiration.wHour, SystemTimeExpiration.wMinute, SystemTimeExpiration.wSecond)); }
//
// Compare the current time to the expiration time
//
LONG CompareResult;
CompareResult = CompareFileTime( pftCurrentTime, pftExpiredTime); //
// If the current time is later than the expired time,
// then we have expired
//
if ( CompareResult > 0 ) { return TRUE; }
return FALSE; }
//
// CAppContainer implementation
//
CAppContainer::CAppContainer()
{ m_fOpen = FALSE;
m_ADsContainer = NULL; m_ADsPackageContainer = NULL;
m_szPackageName = NULL;
memset (&m_PolicyId, 0, sizeof(GUID));
m_KnownMissingClsidCache.sz = 0; m_KnownMissingClsidCache.start = 0; m_KnownMissingClsidCache.end = 0;
m_uRefs = 1;
m_szGpoPath = NULL;
m_pRsopToken = NULL; }
//
// CAppContainer implementation
//
/*----------------------------------------------------------------------*
CAppContainer Constructor:
Parameters: [in] szStoreName: The Class Store Name without 'ADCS:' moniker [out] phr The Error Code returned.
Remarks: Tries to Bind to Base Class Store Container, get the version Number and Packages and Classes container underneath.
Initializes members corresp. to their Names
Return Codes: Success S_OK Failures CS_E_INVALID_VERSION Look at RemapErrorCodes
*----------------------------------------------------------------------*/ CAppContainer::CAppContainer(CServerContext* pServerContext, LPOLESTR szStoreName, PRSOPTOKEN pRsopToken, HRESULT* phr)
{ LPOLESTR pszName = NULL; DWORD dwStoreVersion = 0; LPOLESTR AttrNames[] = {STOREVERSION, POLICYDN}; DWORD posn = 0, cgot = 0; ADS_SEARCHPREF_INFO SearchPrefs[3]; ADS_ATTR_INFO * pAttrsGot = NULL;
m_szGpoPath = NULL;
m_pRsopToken = pRsopToken;
*phr = S_OK;
if ( pServerContext ) { *phr = m_ServerContext.Initialize( pServerContext );
if ( FAILED(*phr) ) { return; } }
// set the search preference for the search Handle
SearchPrefs[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE; SearchPrefs[0].vValue.dwType = ADSTYPE_INTEGER; SearchPrefs[0].vValue.Integer = ADS_SCOPE_ONELEVEL;
SearchPrefs[1].dwSearchPref = ADS_SEARCHPREF_PAGESIZE; SearchPrefs[1].vValue.dwType = ADSTYPE_INTEGER; SearchPrefs[1].vValue.Integer = SEARCHPAGESIZE;
SearchPrefs[2].dwSearchPref = ADS_SEARCHPREF_SECURITY_MASK; SearchPrefs[2].vValue.dwType = ADSTYPE_INTEGER;
SearchPrefs[2].vValue.Integer = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
memset (&m_PolicyId, 0, sizeof(GUID));
m_fOpen = FALSE; m_ADsContainer = NULL; m_ADsPackageContainer = NULL; m_szPackageName = NULL;
memset (&m_PolicyId, 0, sizeof(GUID));
m_KnownMissingClsidCache.sz = 0; m_KnownMissingClsidCache.start = 0; m_KnownMissingClsidCache.end = 0;
m_uRefs = 1; //
// For every interface pointer, we create a separate session
//
// Bind to a Class Store Container Object
// Cache the interface pointer
//
*phr = StringCchCopy (m_szContainerName, _MAX_PATH, szStoreName);
ERROR_ON_FAILURE(*phr);
*phr = DSServerOpenDSObject( &m_ServerContext, m_szContainerName, GetDsFlags(), &m_ADsContainer);
ERROR_ON_FAILURE(*phr); //
// Check the Schema Version of this container
//
*phr = ADSIGetObjectAttributes(m_ADsContainer, AttrNames, 2, &pAttrsGot, &cgot);
if ((SUCCEEDED(*phr)) && (cgot)) {
posn = GetPropertyFromAttr(pAttrsGot, cgot, STOREVERSION); dwStoreVersion = 0; if (posn < cgot) { //
// Ensure that we validate the type of the data return by the ds --
// if the type is not valid (most often this occurs because adsi
// could not create a schema cache on the local machine), we
// will assume it to be invalid. The version number will be
// initialized to 0, which is invalid, and we will abort.
//
if ( ADSTYPE_INTEGER == pAttrsGot[posn].dwADsType ) { UnpackDWFrom(pAttrsGot[posn], &dwStoreVersion); } }
if (dwStoreVersion != SCHEMA_VERSION_NUMBER) { *phr = CS_E_INVALID_VERSION; }
if (SUCCEEDED(*phr)) { LPOLESTR szPolicyPath = NULL;
posn = GetPropertyFromAttr(pAttrsGot, cgot, POLICYDN); if (posn < cgot) { LPOLESTR szParentPath = NULL, szPolicyGuid = NULL;
UnpackStrFrom(pAttrsGot[posn], &szPolicyPath); //
BuildADsParentPath(szPolicyPath, &szParentPath, &szPolicyGuid); if (szParentPath) FreeADsMem(szParentPath);
if (szPolicyGuid) { if (wcslen(szPolicyGuid) == 41) { // valid GUID
GUIDFromString(&szPolicyGuid[4], &m_PolicyId); } FreeADsMem(szPolicyGuid); } } } } else { if (SUCCEEDED(*phr)) { *phr = CS_E_INVALID_VERSION; } }
if (pAttrsGot) FreeADsMem(pAttrsGot);
ERROR_ON_FAILURE(*phr);
//
// Bind to the Package container Object
// Cache the interface pointer
//
BuildADsPathFromParent(m_szContainerName, PACKAGECONTAINERNAME, &m_szPackageName);
m_ADsPackageContainer = NULL;
*phr = DSServerOpenDSObject( &m_ServerContext, m_szPackageName, GetDsFlags(), &m_ADsPackageContainer);
ERROR_ON_FAILURE(*phr);
*phr = ADSISetSearchPreference(m_ADsPackageContainer, SearchPrefs, 3); ERROR_ON_FAILURE(*phr);
m_fOpen = TRUE;
m_uRefs = 1;
m_szGpoPath = AllocGpoPathFromClassStorePath( m_szContainerName );
if ( ! m_szGpoPath ) { *phr = E_OUTOFMEMORY; }
Error_Cleanup: *phr = RemapErrorCode(*phr, m_szContainerName); return; }
/*----------------------------------------------------------------------*
CAppContainer Destructor:
Parameters: None
Function: Destroys CAppContainer object.
Remarks: Frees all the members. Return Codes *----------------------------------------------------------------------*/
CAppContainer::~CAppContainer(void) { UINT i;
if (m_fOpen) { m_fOpen = FALSE; }
if (m_ADsPackageContainer) { ADSICloseDSObject(m_ADsPackageContainer); m_ADsPackageContainer = NULL; FreeADsMem(m_szPackageName); }
if (m_ADsContainer) { ADSICloseDSObject(m_ADsContainer); m_ADsContainer = NULL; }
if (m_szGpoPath) { CsMemFree(m_szGpoPath); } }
//
// Constructor for App Container Class factory
//
unsigned long gulcappcon = 0;
CAppContainerCF::CAppContainerCF() { m_uRefs = 1; InterlockedIncrement((long *) &gulcappcon ); }
//
// Destructor
//
CAppContainerCF::~CAppContainerCF() { //
// Cleanup the cache
//
InterlockedDecrement((long *) &gulcappcon ); }
HRESULT __stdcall CAppContainerCF::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 if( IsEqualIID( IID_IParseDisplayName, riid ) ) { pUnkTemp = (IUnknown *)(IParseDisplayName *)this; } else { sc = (E_NOINTERFACE); }
if((pUnkTemp != NULL) && (SUCCEEDED(sc))) { *ppvObject = (void * )pUnkTemp; pUnkTemp->AddRef(); } return(sc); }
ULONG __stdcall CAppContainerCF::AddRef() { InterlockedIncrement(( long * )&m_uRefs ); return m_uRefs; }
ULONG __stdcall CAppContainerCF::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 CAppContainerCF::CreateInstance(IUnknown * pUnkOuter, REFIID riid, void ** ppvObject) { CAppContainer * pIUnk = NULL; SCODE sc = S_OK;
if( pUnkOuter == NULL ) { if( (pIUnk = new CAppContainer()) != NULL) { sc = pIUnk->QueryInterface( riid , ppvObject ); if(FAILED(sc)) { sc = E_UNEXPECTED; } pIUnk->Release(); } else sc = E_OUTOFMEMORY; } else { return E_INVALIDARG; } return (sc); }
//---------------------------------------------------------------
//
// Function: CreateConnectedInstance
//
// Synopsis: Returns IClassAccess Pointer, given a class store
// path.
//
// Arguments:
// [in]
// pszPath Class Store Path without the leading ADCS:
//
// pUserSid
// Sid under which the calling thread is running.
// fCache
// Boolean that decides whether to use a cached pointer or
// not.
// [out]
// ppvObject
// IClassAccess Interface pointer
//
// Returns:
// S_OK, E_NOINTERFACE, E_OUTOFMEMORY, CS_E_XXX
//
// if (fCache)
// Looks in the cache to see if we have already tried to bind to the same
// ClassStore Path under the same SID. If it finds it, then we just QI for
// IClassAccess and return. o/w create a new class store pointer and caches it.
// else
// Just binds to a new ClassStore and returns.
//----------------------------------------------------------------
HRESULT __stdcall CAppContainerCF::CreateConnectedInstance( CServerContext* pServerContext, LPOLESTR pszPath, PSID pUserSid, PRSOPTOKEN pRsopToken, BOOL fCache, void ** ppvObject) { CAppContainer * pIUnk = NULL; SCODE sc = S_OK; HRESULT hr = S_OK; BOOL fFound = FALSE; FILETIME ftCurrentTime; IClassAccess* pNewClassAccess = NULL;
CBinding* pBinding;
//
// See if we have an existing connection in the cache
//
if (fCache) { GetSystemTimeAsFileTime( &ftCurrentTime ); BindingCache.Lock();
pBinding = BindingCache.Find( pServerContext, &ftCurrentTime, pszPath, pUserSid);
if ( pBinding ) { if ( FAILED( pBinding->Hr ) ) { sc = pBinding->Hr; } else { sc = pBinding->pIClassAccess-> QueryInterface( IID_IClassAccess, ppvObject ); } }
BindingCache.Unlock(); }
if ( fCache && pBinding ) { return sc; }
//
// Couldn't find anything in the cache -- we will have to create a new connection
//
//
// If this is called in the context of policy, ipsec policy may not be enabled.
// Therefore, our communications with the directory would not be secure.
// We will pass TRUE for the secure channel argument of the CAppContainer
// constructor since this code path is exercised during policy and we
// want to ensure security.
//
//
// Note that this object has a refcount of 1 when created
//
if ((pIUnk = new CAppContainer( pServerContext, pszPath, pRsopToken, &sc)) != NULL) { if (SUCCEEDED(sc)) { sc = pIUnk->QueryInterface( IID_IClassAccess, (LPVOID*) &pNewClassAccess ); } else { CSDBGPrint((DM_WARNING, IDS_CSTORE_BIND_FAIL, pszPath, sc)); }
pIUnk->Release(); } else { return E_OUTOFMEMORY; }
//
// Store the result in the cache -- create a binding
// descriptor so we can cache it
//
CBinding* pNewBinding;
if (fCache) { //
// Should not cache situations out of network failures
// For now we are only caching successes OR CS does not exist cases
//
if ((sc == S_OK) || (sc == CS_E_OBJECT_NOTFOUND)) { HRESULT hrBinding;
hrBinding = E_OUTOFMEMORY;
pNewBinding = new CBinding( pServerContext, pszPath, pUserSid, pNewClassAccess, sc, &hrBinding);
if ( FAILED( hrBinding ) ) { sc = hrBinding; fCache = FALSE; } } else { fCache = FALSE; } }
//
// We have the binding descriptor, now cache it
//
if ( fCache ) { CBinding* pBindingAdded;
BindingCache.Lock();
//
// Attempt to add the binding -- if one already
// exists, it will destroy the one we pass in and
// use the existing binding
//
pBindingAdded = BindingCache.AddBinding( &ftCurrentTime, pNewBinding);
sc = pBindingAdded->Hr; if ( SUCCEEDED(sc) ) { sc = pBindingAdded->pIClassAccess-> QueryInterface( IID_IClassAccess, ppvObject ); }
BindingCache.Unlock(); } else { if ( SUCCEEDED(sc) ) { pNewClassAccess->AddRef(); *ppvObject = pNewClassAccess; } }
if ( pNewClassAccess ) { pNewClassAccess->Release(); }
return (sc); }
HRESULT __stdcall CAppContainerCF::LockServer(BOOL fLock) { if(fLock) { InterlockedIncrement((long *) &gulcappcon ); } else { InterlockedDecrement((long *) &gulcappcon ); } return(S_OK); }
//
// IUnknown methods for CAppContainer
//
//
HRESULT __stdcall CAppContainer::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 if( IsEqualIID( IID_IClassRefresh, riid ) ) { pUnkTemp = (IUnknown *)(IClassRefresh *)this; } else if( IsEqualIID( IID_ICatInformation, riid ) ) { pUnkTemp = (IUnknown *)(ICatInformation *)this; } */ else { sc = (E_NOINTERFACE); }
if((pUnkTemp != NULL) && (SUCCEEDED(sc))) { *ppvObject = (void * )pUnkTemp; pUnkTemp->AddRef(); } return(sc); }
ULONG __stdcall CAppContainer::AddRef() { InterlockedIncrement(( long * )&m_uRefs ); return m_uRefs; }
ULONG __stdcall CAppContainer::Release() { unsigned long uTmp = InterlockedDecrement((long *)&m_uRefs); unsigned long cRef = m_uRefs;
if (uTmp == 0) { delete this; }
return(cRef); }
/*----------------------------------------------------------------------*
GetPackageDetails:
Parameters: [in] pszPackageName: The Package Name [out] pPackageDetail Package Detail Structure.
Functionality: Returns the PackageDetail corresp. to a Package given by pszPackageName.
Remarks: It constructs the Full Package Name and calls GetPackageDetail
Return Codes: Success S_OK Failures Look at RemapErrorCodes
*----------------------------------------------------------------------*/
// This is not being called currently by anybody and hence is still using PackageId.
HRESULT CAppContainer::GetPackageDetails ( LPOLESTR pszPackageId, PACKAGEDETAIL *pPackageDetail) { HRESULT hr = S_OK; HANDLE hADs = NULL; WCHAR * szFullName = NULL, szRDN[_MAX_PATH]; ADS_ATTR_INFO * pAttr = NULL; DWORD cgot;
if ((!pszPackageId)) return E_INVALIDARG;
hr = StringCchPrintf(szRDN, _MAX_PATH, L"CN=%s", pszPackageId); ERROR_ON_FAILURE(hr); CSDBGPrint((DM_WARNING, IDS_CSTORE_PKG_DETAILS, szRDN));
BuildADsPathFromParent(m_szPackageName, szRDN, &szFullName);
//
// We do not enforce packet integrity options here because
// this is only called in the context of the admin tool and we
// can rely on ipsec to have executed at that point
//
hr = DSServerOpenDSObject( &m_ServerContext, szFullName, GetDsFlags(), &hADs); ERROR_ON_FAILURE(hr);
hr = GetPackageDetail (hADs, NULL, pPackageDetail);
ADSICloseDSObject(hADs);
if (pAttr) FreeADsMem(pAttr);
if (szFullName) FreeADsMem(szFullName);
Error_Cleanup: return RemapErrorCode(hr, m_szContainerName); }
/*----------------------------------------------------------------------*
EnumPackages
Parameters: [in] pszPackageName Substring match for a package name [in] pCategory Package Category. [in] pLastUsn Last modification time. [in] dwAppFlags Set the following bits to select specific ones Published Only APPINFO_PUBLISHED Assigned Only APPINFO_ASSIGNED Msi Only APPINFO_MSI Visible APPINFO_VISIBLE Auto-Install APPINFO_AUTOINSTALL
All Locale APPINFO_ALLLOCALE All Platform APPINFO_ALLPLATFORM
[out] ppIEnumPackage Returns the Enumerator
Functionality Obtains an enumerator for packages in the app container.
Remarks:
*----------------------------------------------------------------------*/
HRESULT CAppContainer::EnumPackages ( LPOLESTR pszPackageName, GUID *pCategory, ULONGLONG *pLastUsn, DWORD dwQuerySpec, // AppType options
IEnumPackage **ppIEnumPackage ) { const DWORD dwMaxStrLen = 1000; HRESULT hr = S_OK; CEnumPackage *pEnum = NULL; WCHAR szLdapFilter[dwMaxStrLen]; WCHAR szLdapFilterFinal[1500]; UINT len = 0; UINT fFilters = 0; CSPLATFORM *pPlatform = NULL, Platform; DWORD dwAppFlags;
//
// Validate
//
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; }
*ppIEnumPackage = NULL;
pEnum = new CEnumPackage( &m_ServerContext, m_PolicyId, NULL, m_szContainerName, m_pRsopToken ); if(NULL == pEnum) return E_OUTOFMEMORY;
//
// Set client side filters
//
dwAppFlags = ClientSideFilterFromQuerySpec( dwQuerySpec, NULL != m_pRsopToken );
//
// Create a LDAP Search Filter based on input params
//
// Count Filters
if (pszPackageName && (*pszPackageName)) fFilters++; if ((pLastUsn) && (*pLastUsn)) fFilters++; if (pCategory) fFilters++;
if (fFilters == 0) { // No Conditionals
hr = StringCchPrintf (szLdapFilter, dwMaxStrLen, L"(%s=%s)", OBJECTCLASS, CLASS_CS_PACKAGE); ERROR_ON_FAILURE(hr);
len = wcslen (szLdapFilter); } else {
if (fFilters > 1) { hr = StringCchPrintf (szLdapFilter, dwMaxStrLen, L"(&"); ERROR_ON_FAILURE(hr); len = wcslen (szLdapFilter); } else len = 0;
if (pszPackageName) { //
// Validate
//
if (*pszPackageName) { hr = StringCchPrintf (&szLdapFilter[len], dwMaxStrLen - len, L"(%s=*%s*)", PACKAGENAME, pszPackageName); ERROR_ON_FAILURE(hr);
len = wcslen (szLdapFilter); } }
if ((pLastUsn) && (*pLastUsn)) { SYSTEMTIME SystemTime;
FileTimeToSystemTime( (CONST FILETIME *) pLastUsn, &SystemTime);
hr = StringCchPrintf (&szLdapFilter[len], dwMaxStrLen - len, L"(%s>=%04d%02d%02d%02d%02d%02d)", PKGUSN, SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond+1); ERROR_ON_FAILURE(hr);
len = wcslen (szLdapFilter); }
if (pCategory) { STRINGGUID szCat;
StringFromGUID (*pCategory, szCat); hr = StringCchPrintf (&szLdapFilter[len], dwMaxStrLen - len, L"(%s=%s)", PKGCATEGORYLIST, szCat); ERROR_ON_FAILURE(hr);
len = wcslen (szLdapFilter); }
if (fFilters > 1) { if (dwMaxStrLen - len < 2) { hr = STRSAFE_E_INSUFFICIENT_BUFFER; ERROR_ON_FAILURE(hr); } szLdapFilter[len] = L')'; szLdapFilter[++len] = NULL; } }
//
// Finish setting the server side filter
// based on the query type
//
ServerSideFilterFromQuerySpec( dwQuerySpec, NULL != m_pRsopToken, szLdapFilter, szLdapFilterFinal, sizeof(szLdapFilterFinal)/sizeof(szLdapFilterFinal[0]));
CSDBGPrint((DM_WARNING, IDS_CSTORE_ENUMPACKAGE, szLdapFilterFinal, dwAppFlags)); //
// Check all local/platform flags
//
if (!(dwAppFlags & APPFILTER_REQUIRE_THIS_PLATFORM)) { pPlatform = NULL; } else { pPlatform = &Platform; GetDefaultPlatform(pPlatform); }
if (pLastUsn) { //
// Find the current store USN and return it
//
LPOLESTR AttrName = STOREUSN; ADS_ATTR_INFO * pAttr = NULL; DWORD cgot = 0;
hr = ADSIGetObjectAttributes(m_ADsContainer, &AttrName, 1, &pAttr, &cgot); if ((SUCCEEDED(hr)) && (cgot)) { UsnGet(*pAttr, (CSUSN *)pLastUsn); if (pAttr) FreeADsMem(pAttr); } }
hr = pEnum->Initialize(m_szPackageName, szLdapFilterFinal, dwQuerySpec, NULL != m_pRsopToken, pPlatform); ERROR_ON_FAILURE(hr);
hr = pEnum->QueryInterface(IID_IEnumPackage,(void**) ppIEnumPackage); ERROR_ON_FAILURE(hr);
return S_OK;
Error_Cleanup: if (pEnum) delete pEnum; *ppIEnumPackage = NULL;
return RemapErrorCode(hr, m_szContainerName); }
// choosing the best package that can be returned after returning from the DS
DWORD CAppContainer::ChooseBestFit(PACKAGEDISPINFO *PackageInfo, UINT *rgPriority, DWORD cRowsFetched) { DWORD i=0, k=0, j = 0, temp = 0; DWORD index[10];
// initialising the indices
for (i = 0; (i < cRowsFetched); i++) index[i] = i;
// sort the index based on priority and time stamp
for (i = 0; (i < (cRowsFetched-1)); i++) { DWORD Pri = rgPriority[i]; k = i; // max element's index is in k
for (j=(i+1); (j < cRowsFetched); ++j) { // order first by weight and then by time stamp.
if ((rgPriority[index[j]] > Pri) || ((rgPriority[index[j]] == Pri) && (CompareUsn((FILETIME *)&PackageInfo[index[j]].Usn, (FILETIME *)&PackageInfo[index[k]].Usn) == 1))) { Pri = rgPriority[index[j]]; k = j; } }
if (k != i) { temp = index[k]; index[k] = index[i]; index[i] = temp; } }
DWORD dwPackage; DWORD dwBestPackage;
dwBestPackage = 0;
//
// Now the packages are sorted in order from highest precedence to lowest.
// We will now check for upgrades for each package
//
for (dwPackage = 0; (dwPackage < cRowsFetched); dwPackage++) { DWORD dwPossibleUpgrader; PACKAGEDISPINFO* pBestPackage;
pBestPackage = PackageInfo+index[dwBestPackage];
CSDBGPrint((DM_WARNING, IDS_CSTORE_BESTFIT, pBestPackage->pszPackageName));
//
// Now search for someone that upgrades the current choice -- look at all packages
// after the current one since we've already determined that the packages before
// this one got upgraded (otherwise we wouldn't be here).
//
for (dwPossibleUpgrader = dwPackage + 1; dwPossibleUpgrader < cRowsFetched; dwPossibleUpgrader ++) { PACKAGEDISPINFO* pUpgraderCandidate;
//
// Obviously, we don't need to check the current choice
// to see if it upgrades itself, so skip it
//
if (dwPossibleUpgrader == dwBestPackage) { continue; }
pUpgraderCandidate = PackageInfo + index[dwPossibleUpgrader];
//
// See if the upgrader candidate has any upgrades, if not, keep looking
//
if (0 == pUpgraderCandidate->cUpgrades) { continue; }
//
// Now we have to see if any of those upgrades apply to the package we have
// currently selected as the best
//
DWORD dwUpgrade; BOOL fFoundUpgrade;
fFoundUpgrade = FALSE;
for (dwUpgrade = 0; dwUpgrade < pUpgraderCandidate->cUpgrades; dwUpgrade++) { DWORD dwValidUpgradeMask;
dwValidUpgradeMask = UPGFLG_Uninstall | UPGFLG_NoUninstall | UPGFLG_Enforced;
//
// If this is a valid upgrade
//
if (pUpgraderCandidate->prgUpgradeInfoList[dwUpgrade].Flag & dwValidUpgradeMask) { //
// Does it upgrade the package we think is best at this point? We only
// consider upgrades in this container, as we no longer allow upgrades from lower
// precedence class stores -- the caller who iterates through each container from
// highest precedence to lowest will simply choose the app from the first container in which
// we have a match.
//
// We use memcmp to compare guids to see if the best choice package's guid is listed
// as being upgraded by this upgrade candidate
//
if (memcmp(&((pUpgraderCandidate->prgUpgradeInfoList)[dwUpgrade].PackageGuid), &(pBestPackage->PackageGuid), sizeof(GUID) == 0)) { //
// We have a match -- reset the current best choice to the upgrade candidate
//
dwBestPackage = dwPossibleUpgrader;
//
// another package upgrades this -- no need to look any further, so we quit
//
CSDBGPrint((DM_WARNING, IDS_CSTORE_BESTFITSKIP, pBestPackage->pszPackageName, pUpgraderCandidate->pszPackageName));
break; } } }
//
// If we found an upgrade in the list above, we can stop abort the search for an upgrade now --
// if we found another, it would just be a lower precedence app since we're iterating from highest to lowest,
// and we want the highest predecence app that upgrades the currently chosen best app
//
if (fFoundUpgrade) { break; } } }
DWORD dwChoice;
dwChoice = index[dwBestPackage];
CSDBGPrint((DM_WARNING, IDS_CSTORE_BESTFIT_END, PackageInfo[dwChoice].pszPackageName));
return dwChoice; }
//
// CAppContainer::GetAppInfo
// -----------------------------
//
//
//
// Synopsis: This is the most common access point to the Class Store.
// It receives a CLSID and a QUERYCONTEXT.
// It looks up the Class Store container for a matching set
// of packages with in the context of the QUERYCONTEXT.
//
// QUERYCONTEXT includes
// Execution Context
// Locale Id
// Platform/OS
//
// If i finds an app that matches the requirements, it returns
// an PACKAGEDISPINFO structure containing installation details.
//
// Arguments: [in] clsid
// [in] pQryContext
// [out] pPackageInfo
//
// Returns: CS_E_PACKAGE_NOTFOUND
// S_OK
//
//
//
HRESULT STDMETHODCALLTYPE CAppContainer::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.
//
// If a matching implementation is available (for the object type,
// client architecture, locale and class context) then the installation
// parameters of the package is returned.
{ const DWORD dwMaxStrLen = 1000; GUID clsid; WCHAR szfilterbuf[dwMaxStrLen]; WCHAR* szfilter = szfilterbuf; WCHAR* szNameFilter; STRINGGUID szClsid; UINT i, iClsid = 0; ULONG cRead; HRESULT hr; ULONG cSize = _MAX_PATH; BOOL fFound = FALSE; PLATFORMINFO PlatformInfo; LPOLESTR pFileExt = NULL; BOOL OnDemandInstallOnly = TRUE; WCHAR FileExtLower [10]; FILETIME ftCurrentTime;
szNameFilter = NULL;
memset(pPackageInfo, 0, sizeof(PACKAGEDISPINFO));
if (!m_fOpen) return E_FAIL;
//
// Check if the TypeSpec is MIMEType
// then map it to a CLSID
//
switch (pclsspec->tyspec) { case TYSPEC_CLSID:
if (IsNullGuid(pclsspec->tagged_union.clsid)) return E_INVALIDARG; //
// Check against known missing ones
//
hr = S_OK;
EnterCriticalSection (&ClassStoreBindList);
//
// Retrieve the current time so we can determine
// if cache entries are expired
//
GetSystemTimeAsFileTime( &ftCurrentTime );
for (iClsid=m_KnownMissingClsidCache.start; (iClsid != m_KnownMissingClsidCache.end); iClsid = (iClsid+1)%(CLSIDCACHESIZE)) { if ( IsExpired( &ftCurrentTime, &(m_KnownMissingClsidCache.ElemArr[iClsid].Time) ) ) { // all the prev. elems must have expired.
// delete this element
m_KnownMissingClsidCache.start = (m_KnownMissingClsidCache.start+1)%CLSIDCACHESIZE; m_KnownMissingClsidCache.sz--;
CSDBGPrint((DM_WARNING, IDS_CSTORE_CLASS_PURGE)); // iClsid will be moved automatically.
continue; }
if ((IsEqualGUID(pclsspec->tagged_union.clsid, m_KnownMissingClsidCache.ElemArr[iClsid].Clsid)) && ((pQryContext->dwContext) == m_KnownMissingClsidCache.ElemArr[iClsid].Ctx)) { CSDBGPrint((DM_WARNING, IDS_CSTORE_CLASS_HIT));
hr = CS_E_PACKAGE_NOTFOUND; break; } }
LeaveCriticalSection (&ClassStoreBindList);
if (hr == CS_E_PACKAGE_NOTFOUND) return hr;
StringFromGUID (pclsspec->tagged_union.clsid, szClsid); hr = StringCchPrintf (szfilter, dwMaxStrLen, L"(%s=%s*)", PKGCLSIDLIST, szClsid); if (FAILED(hr)) { return hr; } break;
case TYSPEC_FILEEXT:
if ((pclsspec->tagged_union.pFileExt == NULL) || (*(pclsspec->tagged_union.pFileExt) == NULL)) return E_INVALIDARG;
if (wcslen(pclsspec->tagged_union.pFileExt) > 9) return E_INVALIDARG;
hr = StringCbCopy (&FileExtLower[0], sizeof(FileExtLower), pclsspec->tagged_union.pFileExt); if (FAILED(hr)) { return hr; }
_wcslwr (&FileExtLower[0]);
hr = StringCchPrintf (szfilter, dwMaxStrLen, L"(%s=%s*)", PKGFILEEXTNLIST, &FileExtLower[0]); if (FAILED(hr)) { return hr; }
pFileExt = &FileExtLower[0]; break;
case TYSPEC_PROGID:
if ((pclsspec->tagged_union.pProgId == NULL) || (*(pclsspec->tagged_union.pProgId) == NULL)) return E_INVALIDARG;
hr = StringCchPrintf (szfilter, dwMaxStrLen, L"(%s=%s)", PKGPROGIDLIST, pclsspec->tagged_union.pProgId); if (FAILED(hr)) { return hr; }
break;
case TYSPEC_PACKAGENAME: //
// Validate package name
//
if ((pclsspec->tagged_union.ByName.pPackageName == NULL) || (*(pclsspec->tagged_union.ByName.pPackageName) == NULL)) return E_INVALIDARG;
//
// The search filter syntax requires that the package name is
// properly escaped, so we retrieve such a filter below
//
hr = GetEscapedNameFilter( pclsspec->tagged_union.ByName.pPackageName, &szNameFilter );
if ( FAILED(hr) ) { return hr; }
szfilter = szNameFilter;
OnDemandInstallOnly = FALSE; break;
case TYSPEC_OBJECTID: //
// Validate object id
//
if (IsNullGuid(pclsspec->tagged_union.ByObjectId.ObjectId)) return E_INVALIDARG;
LPWSTR EncodedGuid;
EncodedGuid = NULL; hr = ADsEncodeBinaryData((PBYTE)&pclsspec->tagged_union.ByObjectId.ObjectId, sizeof(GUID), &EncodedGuid); hr = StringCchPrintf(szfilter, dwMaxStrLen, L"(%s=%s)", OBJECTGUID, EncodedGuid); FreeADsMem(EncodedGuid); OnDemandInstallOnly = FALSE; if (FAILED(hr)) { return hr; }
break;
default: return E_NOTIMPL; }
//
//
ULONG cRowsFetched; PACKAGEDISPINFO PackageInfo[10]; UINT rgPriority [10];
ADS_SEARCH_HANDLE hADsSearchHandle = NULL;
hr = ADSIExecuteSearch(m_ADsPackageContainer, szfilter, pszInstallInfoAttrNames, cInstallInfoAttr, &hADsSearchHandle);
CSDBGPrint((DM_WARNING, IDS_CSTORE_MERGEAPPINFO, szfilter));
ERROR_ON_FAILURE(hr);
//
// We obtain the 10 best matches
//
hr = FetchInstallData( m_ADsPackageContainer, hADsSearchHandle, pQryContext, pclsspec, pFileExt, 10, &cRowsFetched, &PackageInfo[0], &rgPriority[0], OnDemandInstallOnly, &m_PolicyId, m_szGpoPath );
CSDBGPrint((DM_WARNING, IDS_CSTORE_ONDEMAND, cRowsFetched, hr));
if (cRowsFetched == 0) { hr = CS_E_OBJECT_NOTFOUND; //
// If CLSID was passed cache the miss
//
if (pclsspec->tyspec == TYSPEC_CLSID) { EnterCriticalSection (&ClassStoreBindList);
if (m_KnownMissingClsidCache.sz < (CLSIDCACHESIZE-1)) { memcpy (&m_KnownMissingClsidCache.ElemArr[m_KnownMissingClsidCache.end].Clsid, &(pclsspec->tagged_union.clsid), sizeof(GUID));
m_KnownMissingClsidCache.ElemArr[m_KnownMissingClsidCache.end].Ctx = pQryContext->dwContext;
//
// Set the time member to the current time -- this is retrieved
// above for all clsid queries
//
GetExpiredTime( &ftCurrentTime, &(m_KnownMissingClsidCache.ElemArr[m_KnownMissingClsidCache.end].Time) );
m_KnownMissingClsidCache.sz++;
m_KnownMissingClsidCache.end = (m_KnownMissingClsidCache.end+1) % CLSIDCACHESIZE;
} LeaveCriticalSection (&ClassStoreBindList); } } else { DWORD dwChoice = 0;
if (cRowsFetched > 1) { dwChoice = ChooseBestFit(PackageInfo, rgPriority, cRowsFetched); }
memcpy (pPackageInfo, &PackageInfo[dwChoice], sizeof(PACKAGEDISPINFO)); memset (&PackageInfo[dwChoice], NULL, sizeof(PACKAGEDISPINFO));
// Clean up all allocations
for (i=0; i < cRowsFetched; i++) { ReleasePackageInfo(&PackageInfo[i]); } }
if (hADsSearchHandle) ADSICloseSearchHandle(m_ADsPackageContainer, hADsSearchHandle);
//
// fill in PolicyID
//
if (SUCCEEDED(hr)) { memcpy (&(pPackageInfo->GpoId), &m_PolicyId, sizeof(GUID)); }
Error_Cleanup:
if ( szNameFilter ) { CsMemFree( szNameFilter ); } CSDBGPrint((DM_WARNING, IDS_CSTORE_APPINFO_END, hr));
return RemapErrorCode(hr, m_szContainerName); }
|