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.
 
 
 
 
 
 

10037 lines
303 KiB

/*++
Copyright (C) 1996-2001 Microsoft Corporation
Module Name:
WBEMNAME.CPP
Abstract:
Implements the COM layer of WINMGMT --- the class representing a namespace.
It is defined in wbemname.h
History:
raymcc 05-Apr-96 Created.
raymcc 23-Apr-00 Whistler extensions
--*/
#include "precomp.h"
#pragma warning (disable : 4786)
#include <wbemcore.h>
#include <map>
#include <vector>
#include <genutils.h>
#include <oahelp.inl>
#include <wqllex.h>
#include <autoptr.h>
#include <comutl.h>
#include <helper.h>
#include "wmiarbitrator.h"
#include "wmifinalizer.h"
#include "wmimerger.h"
#ifdef DBG
TimeTraces gTimeTraceHistory;
CStaticCritSec OperationStat::lock_;
#endif
extern BOOL g_bDontAllowNewConnections;
//***************************************************************************
//
//***************************************************************************
#define WBEM_MASK_DEPTH (WBEM_FLAG_DEEP | WBEM_FLAG_SHALLOW)
#define WBEM_MASK_CREATE_UPDATE (WBEM_FLAG_CREATE_ONLY | WBEM_FLAG_UPDATE_ONLY | WBEM_FLAG_CREATE_OR_UPDATE)
bool illFormatedClass2 (const wchar_t * pszSuperclass)
{
for (const wchar_t * p = pszSuperclass; *p != L'\0'; ++p)
{
if (!(isunialphanum (*p) || *p == L'_'))
{
return true; //Ill formated
}
}
return false;
};
HRESULT IsDerivedFromSystem(CWbemObject& obj, bool * result)
{
*result = true;
CVar vClass;
HRESULT hr = obj.GetClassName(&vClass);
if (FAILED(hr)) return hr;
wchar_t * className = vClass.GetLPWSTR();
if (className[0] == L'_') return S_OK;
CVar vDeriv;
hr = obj.GetDerivation(&vDeriv);
if (FAILED(hr)) return hr;
CVarVector *pvTemp = vDeriv.GetVarVector();
for (int j = 0; j < pvTemp->Size(); j++)
{
CVar& vParentName = pvTemp->GetAt(j);
wchar_t * parentName = vParentName.GetLPWSTR();
if (parentName[0] == L'_')
{
return S_OK;
}
}
*result = false;
return S_OK;
};
//***************************************************************************
//
// StripServer
// if the string is \\SOMETHING\namespace1\namespace2
// returns namespace1\namespace2
// but it pre-allocates \\.\ in front of it, so that you can move back the pointer
//
//***************************************************************************
LPWSTR StripServer(LPWSTR pszNamespace)
{
LPWSTR lpRet = NULL;
WCHAR * lpPtr = pszNamespace;
if (*lpPtr == L'\\' || *lpPtr == L'/')
{
lpPtr++;
if (*lpPtr == L'\\' || *lpPtr == L'/')
{
BOOL bSlash = FALSE;
while (*lpPtr)
{
lpPtr++;
if (*lpPtr == L'\\' || *lpPtr == L'/')
{
bSlash = TRUE;
break;
}
}
if (bSlash)
{
lpPtr++;
size_t tmpSize = 4 + wcslen(lpPtr) + 1;
WCHAR * pFull = new WCHAR[tmpSize];
if (NULL == pFull) return pFull;
StringCchCopyW(pFull,tmpSize,L"\\\\.\\");
StringCchCopyW(pFull+4,tmpSize-4,lpPtr);
lpRet = pFull;
}
}
}
if (!lpRet)
{
size_t tmpSize = 4 + wcslen(lpPtr) + 1;
WCHAR * pFull = new WCHAR[tmpSize];
if (NULL == pFull) return pFull;
StringCchCopyW(pFull,tmpSize,L"\\\\.\\");
StringCchCopyW(pFull+4,tmpSize-4,lpPtr);
lpRet = pFull;
}
return lpRet;
}
//
//
//
///////////////////////////////////////////////////////////////
class CSecureEssNamespaceSink
: public CUnkBase<IWbemObjectSink, &IID_IWbemObjectSink>
{
CWbemPtr<CWbemNamespace> m_pNamespace;
CWbemPtr<IWbemObjectSink> m_pSink;
public:
CSecureEssNamespaceSink( CWbemNamespace* pNamespace,
IWbemObjectSink* pSink )
: m_pNamespace(pNamespace), m_pSink(pSink) {}
STDMETHOD(Indicate)(long lObjectCount, IWbemClassObject** pObjArray)
{
HRESULT hRes = m_pNamespace->CheckNs();
if (FAILED(hRes))
return hRes;
if ( !m_pNamespace->Allowed( WBEM_FULL_WRITE_REP ) )
return WBEM_E_ACCESS_DENIED;
return m_pSink->Indicate( lObjectCount, pObjArray );
}
STDMETHOD(SetStatus)(long a, long b, BSTR c, IWbemClassObject* d)
{
HRESULT hRes = m_pNamespace->CheckNs();
if (FAILED(hRes))
return hRes;
if ( !m_pNamespace->Allowed( WBEM_FULL_WRITE_REP ) )
return WBEM_E_ACCESS_DENIED;
return m_pSink->SetStatus( a, b, c, d );
}
};
//***************************************************************************
//
//***************************************************************************
//
CWbemNamespace::CWbemNamespace()
{
m_uSecondaryRefCount = 0;
m_bShutDown = FALSE;
m_pSession = 0;
m_pDriver = 0;
m_pNsHandle = 0;
m_pScopeHandle = 0;
m_pThisNamespace = 0;
m_pThisNamespaceFull = 0;
m_dwPermission = 0;
m_dwSecurityFlags = 0;
m_wszUserName = 0;
m_bProvider = FALSE;
m_bForClient = FALSE;
m_bESS = FALSE;
m_bSecurityInitialized = FALSE;
m_pProvFact = 0;
m_pCoreSvc = 0;
m_bRepositOnly = FALSE;
m_pRefreshingSvc = NULL;
m_pszClientMachineName = NULL;
m_dwClientProcessID = -1;
m_pArb = CWmiArbitrator::GetRefedArbitrator();
m_pArb->RegisterNamespace((_IWmiCoreHandle *)this);
gClientCounter.AddClientPtr(&m_Entry);
}
//***************************************************************************
//
//***************************************************************************
//
CWbemNamespace *CWbemNamespace::CreateInstance()
{
try
{
if (NULL == CWmiArbitrator::GetUnrefedArbitrator()) return NULL;
CWbemNamespace *pNs = new CWbemNamespace;
if (pNs) pNs->AddRef();
return pNs;
}
catch(CX_Exception &)
{
return 0;
}
}
//***************************************************************************
//
// CWbemNamespace::Initialize
//
// Real constructor. In addition to finding the namespace in the database, this
// function also enumerates all the class providers in the namespace and
// loads them. It also notifies the ESS of the opening.
//
// PARAMETERS:
//
// LPWSTR Namespace The full of the namespace to create.
//
// RETURN VALUES:
//
// Even though this function has no return values, it indicates success
// or failure by setting the Status member variable to the error code.
// WBEM_S_NO_ERROR On Success
// WBEM_E_INVALID_NAMESPACE No such namespace
// WBEM_E_CRITICAL_ERROR Other database error.
//
//***************************************************************************
HRESULT CWbemNamespace::Initialize(
LPWSTR pszNamespace,
LPWSTR wszUserName,
DWORD dwSecFlags,
DWORD dwPermission,
BOOL bForClient,
BOOL bRepositOnly,
LPCWSTR pszClientMachineName,
DWORD dwClientProcessID,
BOOL bSkipSDInitialize,
IWmiDbSession *pParentSession)
{
try
{
m_dwSecurityFlags = dwSecFlags;
m_dwPermission = dwPermission;
if(g_bDontAllowNewConnections)
return WBEM_E_SHUTTING_DOWN;
PSID pRawSid;
SID_IDENTIFIER_AUTHORITY id = SECURITY_NT_AUTHORITY;
if (!AllocateAndInitializeSid( &id, 2, // SEC:REVIEWED 2002-03-22 : OK
SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,
0,0,0,0,0,0,&pRawSid))
return WBEM_E_OUT_OF_MEMORY;
CNtSid Sid(pRawSid);
FreeSid( pRawSid );
if (CNtSid::NoError != Sid.GetStatus()) return WBEM_E_OUT_OF_MEMORY;
CNtAce ace(1,ACCESS_ALLOWED_ACE_TYPE,0,Sid);
if(ace.GetStatus() != 0)
return WBEM_E_OUT_OF_MEMORY;
CNtAcl acl;
acl.AddAce(&ace);
m_sdCheckAdmin.SetDacl(&acl);
CNtSid owner(CNtSid::CURRENT_USER);
if (CNtSid::NoError != owner.GetStatus()) return WBEM_E_OUT_OF_MEMORY;
m_sdCheckAdmin.SetGroup(&owner);
m_sdCheckAdmin.SetOwner(&owner);
m_bForClient = bForClient;
m_pThisNamespaceFull = StripServer(pszNamespace);
if(m_pThisNamespaceFull == NULL) return WBEM_E_OUT_OF_MEMORY;
m_pThisNamespace = m_pThisNamespaceFull + 4; // move past "\\.\"
m_pCoreSvc = CCoreServices::CreateInstance();
if(m_pCoreSvc == NULL)
return WBEM_E_OUT_OF_MEMORY;
m_pProvFact = 0;
m_bRepositOnly = bRepositOnly;
// Flip the slashes
// ================
WCHAR* pwc = m_pThisNamespace;
while(*pwc)
{
if(*pwc == '/')
*pwc = '\\';
pwc++;
}
m_wszUserName = (wszUserName?Macro_CloneLPWSTR(wszUserName):NULL);
// Repository binding.
// ===================
m_pNsHandle = 0;
HRESULT hRes;
IWmiDbSession *pTempSession= pParentSession;
if (pTempSession == NULL)
{
hRes = CRepository::GetDefaultSession(&pTempSession);
if (FAILED(hRes)) return hRes;
}
else
pTempSession->AddRef();
CReleaseMe rmSession(pTempSession);
hRes = CRepository::OpenScope(pTempSession, m_pThisNamespace, 0, &m_pDriver, &m_pSession, &m_pScopeHandle, &m_pNsHandle);
if (FAILED(hRes))
{
Status = WBEM_E_INVALID_NAMESPACE;
return hRes;
}
if (m_pScopeHandle == 0)
{
m_bSubscope = FALSE;
m_pScopeHandle = m_pNsHandle;
if(m_pScopeHandle == NULL)
{
ERRORTRACE((LOG_WBEMCORE, "OpenScope returned success, yet m_pNsHandle is null!\n"));
return WBEM_E_CRITICAL_ERROR;
}
m_pScopeHandle->AddRef();
}
else
{
#ifdef DBG
DebugBreak();
#endif
m_bSubscope = TRUE;
return WBEM_E_INVALID_NAMESPACE;
}
m_pProvFact = 0;
if (!bRepositOnly)
{
_IWmiProvSS *pProvSS = 0;
m_pCoreSvc->GetProviderSubsystem(0, &pProvSS);
CReleaseMe _(pProvSS);
if(pProvSS)
{
HRESULT hr = pProvSS->Create(
this, // Stupid because v-table access can occur before constructor completion
0, // lFlags
0, // pCtx
m_pThisNamespace, // Path
IID__IWmiProviderFactory,
(LPVOID *) &m_pProvFact
);
if (FAILED(hr)) return hr ;
}
}
if(pszClientMachineName)
{
delete m_pszClientMachineName;
DUP_STRING_NEW(m_pszClientMachineName, pszClientMachineName);
if(m_pszClientMachineName == NULL)
return WBEM_E_OUT_OF_MEMORY;
}
m_dwClientProcessID = dwClientProcessID;
Status = WBEM_S_NO_ERROR;
//Initialize Security descriptor
if (!bSkipSDInitialize)
{
hRes = InitializeSD(pTempSession);
if (FAILED(hRes)) return hRes;
}
m_pCoreSvc->IncrementCounter(WMICORE_SELFINST_CONNECTIONS, 1);
return Status;
}
catch(...)
{
ExceptionCounter c;
return WBEM_E_FAILED;
}
}
//***************************************************************************
//
// CWbemNamespace::~CWbemNamespace
//
// Notifies the ESS of namespace closure and frees up all the class providers.
//
//***************************************************************************
CWbemNamespace::~CWbemNamespace()
{
// do this before releasing the arbitrator
m_pArb->UnregisterNamespace((_IWmiCoreHandle *)this);
if (m_pCoreSvc)
m_pCoreSvc->DecrementCounter(WMICORE_SELFINST_CONNECTIONS, 1);
ReleaseIfNotNULL(m_pProvFact);
ReleaseIfNotNULL(m_pCoreSvc);
ReleaseIfNotNULL(m_pSession);
ReleaseIfNotNULL(m_pDriver);
ReleaseIfNotNULL(m_pNsHandle);
ReleaseIfNotNULL(m_pScopeHandle);
ReleaseIfNotNULL(m_pRefreshingSvc);
ReleaseIfNotNULL(m_pArb);
DeleteAndNull(m_pThisNamespaceFull);
DeleteAndNull(m_wszUserName);
DeleteAndNull(m_pszClientMachineName);
gClientCounter.RemoveClientPtr(&m_Entry);
}
//***************************************************************************
//
// CWbemNamespace::QueryInterface
//
// Exports IWbemServices interface.
//
//***************************************************************************
STDMETHODIMP CWbemNamespace::QueryInterface(
IN REFIID riid,
OUT LPVOID *ppvObj
)
{
*ppvObj = 0;
if (IID_IUnknown==riid || IID_IWbemServices==riid )
{
*ppvObj = (IWbemServices*)this;
AddRef();
return S_OK;
}
else if (IID_IWbemRefreshingServices == riid)
{
CInCritSec ics(&m_cs);
// Check if we already have this one
if ( NULL == m_pRefreshingSvc )
{
IUnknown * pUnk = NULL;
// Aggregate this interface - We MUST use IUnknown, so the aggregee does not AddRef us.
HRESULT hr = CoCreateInstance( CLSID__WbemConfigureRefreshingSvcs, // SEC:REVIEWED 2002-03-22 : OK
(IWbemServices*) this, CLSCTX_INPROC_SERVER,
IID_IUnknown, (void**) &pUnk );
if (FAILED(hr)) return hr;
OnDeleteIf<IUnknown *,void(*)(IUnknown *),RM> rmUnk(pUnk);
_IWbemConfigureRefreshingSvcs* pCfgRefrSvc = NULL;
hr = pUnk->QueryInterface( IID__IWbemConfigureRefreshingSvcs, (void**) &pCfgRefrSvc );
if (FAILED(hr)) return hr;
CReleaseMe rm(pCfgRefrSvc);
// Use BSTR's in case any marshaling takes place
BSTR pstrMachineName = SysAllocString( ConfigMgr::GetMachineName() );
if (NULL == pstrMachineName) return E_OUTOFMEMORY;
CSysFreeMe sfm1( pstrMachineName );
BSTR pstrNamespace = SysAllocString( m_pThisNamespace );
if (NULL == pstrNamespace) return E_OUTOFMEMORY;
CSysFreeMe sfm2( pstrNamespace );
hr = pCfgRefrSvc->SetServiceData( pstrMachineName, pstrNamespace );
if (FAILED(hr)) return hr;
// compensate the Automatic Objects above
m_pRefreshingSvc = pUnk;
rmUnk.dismiss();
}
return m_pRefreshingSvc->QueryInterface( IID_IWbemRefreshingServices, ppvObj );
}
else if(IID_IWbemInternalServices == riid)
{
*ppvObj = (IWbemInternalServices*)this;
AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
//***************************************************************************
//
//***************************************************************************
//
ULONG CWbemNamespace::AddRef()
{
ULONG uNewCount = InterlockedIncrement((LONG *) &m_uSecondaryRefCount);
return uNewCount;
}
//***************************************************************************
//
//***************************************************************************
//
ULONG CWbemNamespace::Release()
{
ULONG uNewCount = InterlockedDecrement((LONG *) &m_uSecondaryRefCount);
if (0 == uNewCount) delete this;
return uNewCount;
}
//***************************************************************************
//
//***************************************************************************
//
HRESULT CWbemNamespace::Dump(FILE *f)
{
// SEC:REVIEWED 2002-03-22 : OK; debugging use only
fprintf(f, "---Namespace = 0x%p----------------------------\n", this); // SEC:REVIEWED 2002-03-22 : OK
fprintf(f, " Secondary Refcount = %d\n", m_uSecondaryRefCount); // SEC:REVIEWED 2002-03-22 : OK
if(m_pThisNamespace)
fprintf(f, " Name = %ls\n", m_pThisNamespace); // SEC:REVIEWED 2002-03-22 : OK
if(m_wszUserName)
fprintf(f, " User Name = %ls\n", m_wszUserName); // SEC:REVIEWED 2002-03-22 : OK
if(m_pszClientMachineName)
fprintf(f, " Client Machine Name = %ls\n", m_pszClientMachineName); // SEC:REVIEWED 2002-03-22 : OK
else
fprintf(f, " Client Machine Name = <unknown>\n"); // SEC:REVIEWED 2002-03-22 : OK
if(m_dwClientProcessID)
fprintf(f, " Client Process = 0X%X\n", m_dwClientProcessID); // SEC:REVIEWED 2002-03-22 : OK
else
fprintf(f, " Client Process = <unknown>\n"); // SEC:REVIEWED 2002-03-22 : OK
return S_OK;
}
//***************************************************************************
//
//***************************************************************************
//
/*
HRESULT CWbemNamespace::SetErrorObj(IWbemClassObject* pErrorObj)
{
if (pErrorObj == NULL)
{
return S_OK;
}
IErrorInfo* pInfo;
HRESULT hRes = pErrorObj->QueryInterface(IID_IErrorInfo, (void**)&pInfo);
if (FAILED(hRes))
return hRes;
hRes = SetErrorInfo(0, pInfo);
pInfo->Release();
return hRes;
}
*/
//***************************************************************************
//
// CWbemNamespace::SplitLocalized
//
//***************************************************************************
HRESULT CWbemNamespace::SplitLocalized (
CWbemObject *pOriginal,
CWbemObject *pStoredObj
)
{
HRESULT hres = 0;
CVar vProv;
IWbemQualifierSet *pOrigQs = NULL, *pStoredQs = NULL;
VARIANT vVal;
VariantInit(&vVal);
hres = pOriginal->GetQualifierSet(&pOrigQs);
if (FAILED(hres))
return hres;
if (pStoredObj)
{
hres = pStoredObj->GetQualifierSet(&pStoredQs);
if (FAILED(hres))
{
pOrigQs->Release();
return hres;
}
}
hres = FixAmendedQualifiers(pOrigQs, pStoredQs);
pOrigQs->Release();
pOrigQs = NULL;
if (pStoredQs)
{
pStoredQs->Release();
pStoredQs = NULL;
}
if (SUCCEEDED(hres))
{
pOriginal->BeginEnumeration(0);
LONG lLong;
CIMTYPE ct;
VARIANT vNewVal;
VariantInit(&vNewVal);
BSTR strPropName = NULL;
while((hres = pOriginal->Next(0, &strPropName, &vNewVal, &ct, &lLong)) == S_OK)
{
CSysFreeMe sfm(strPropName);
CClearMe ccm(&vNewVal);
CWStringArray arrDel;
pOrigQs = NULL;
pStoredQs = NULL;
// Ignore system qualifiers.
if (strPropName[0] == L'_')
{
continue;
}
hres = pOriginal->GetPropertyQualifierSet(strPropName, &pOrigQs);
if (FAILED(hres))
{
return hres;
}
pStoredQs = NULL;
if (pStoredObj)
{
pStoredObj->GetPropertyQualifierSet(strPropName, &pStoredQs);
}
hres = FixAmendedQualifiers(pOrigQs, pStoredQs);
pOrigQs->Release();
if (pStoredQs)
pStoredQs->Release();
}
pOriginal->EndEnumeration();
// Unfortunately, we have to enumerate the methods,
// and *then* update them...
BSTR bstrMethodName;
pOriginal->BeginMethodEnumeration(0);
IWbemClassObject *pLIn = NULL, *pLOut = NULL, *pOIn = NULL, *pOOut = NULL;
// first count the number of methods
while ( pOriginal->NextMethod( 0, &bstrMethodName, 0, 0 ) == S_OK )
{
pLIn = pLOut = pOIn = pOOut = NULL;
pOrigQs = NULL ;
pStoredQs = NULL ;
hres = pOriginal->GetMethod(bstrMethodName, 0, &pLIn, &pLOut);
if ( FAILED ( hres ) )
{
continue ;
}
CSysFreeMe fm(bstrMethodName);
CReleaseMe rm0(pLIn);
CReleaseMe rm2(pLOut);
hres = pOriginal->GetMethodQualifierSet(bstrMethodName, &pOrigQs);
if (FAILED(hres))
{
continue;
}
CReleaseMe rm4 ( pOrigQs ) ;
if (pStoredObj)
{
hres = pStoredObj->GetMethodQualifierSet(bstrMethodName, &pStoredQs);
if ( FAILED ( hres ) )
{
continue ;
}
}
CReleaseMe rm5 ( pStoredQs ) ;
// Method qualifiers...
hres = FixAmendedQualifiers(pOrigQs, pStoredQs);
if (SUCCEEDED(hres))
{
if (pStoredObj)
hres = pStoredObj->GetMethod(bstrMethodName, 0, &pOIn, &pOOut);
CReleaseMe rm1(pOIn);
CReleaseMe rm3(pOOut);
if (pLIn)
hres = SplitLocalized((CWbemObject *)pLIn, (CWbemObject *)pOIn);
if (pLOut)
hres = SplitLocalized((CWbemObject *)pLOut, (CWbemObject *)pOOut);
hres = pOriginal->PutMethod(bstrMethodName, 0, pLIn, pLOut);
}
else
break;
}
pOriginal->EndMethodEnumeration();
}
hres = 0;
return hres;
}
//***************************************************************************
//
// CWbemNamespace::FixAmendedQualifiers
//
//***************************************************************************
HRESULT CWbemNamespace::FixAmendedQualifiers(
IWbemQualifierSet *pOriginal,
IWbemQualifierSet *pNew
)
{
HRESULT hres = 0;
CWStringArray arrDelete;
CWStringArray arrProps;
BSTR strName = 0;
long lFlavor;
int i;
pOriginal->BeginEnumeration(0);
// BUGBUG EndEnum
while(pOriginal->Next(0, &strName, NULL, NULL) == S_OK)
{
CSysFreeMe sfm(strName);
if (CFlexArray::no_error != arrProps.Add(strName))
return WBEM_E_OUT_OF_MEMORY;
}
for (i = 0; i < arrProps.Size(); i++)
{
_variant_t vVal;
pOriginal->Get(arrProps.GetAt(i), 0, &vVal, &lFlavor);
if (lFlavor & WBEM_FLAVOR_AMENDED)
{
// Delete the "amended" qualifier.
if (CFlexArray::no_error != arrDelete.Add(arrProps.GetAt(i)))
return WBEM_E_OUT_OF_MEMORY;
// Restore any original qualifier value.
if (pNew)
{
_variant_t vOldVal;
long lOldFlavor;
if (pNew->Get(arrProps.GetAt(i), 0, &vOldVal, &lOldFlavor) != WBEM_E_NOT_FOUND)
{
pOriginal->Put(arrProps.GetAt(i), &vOldVal, lOldFlavor);
arrDelete.RemoveAt(arrDelete.Size()-1);
}
}
}
}
pOriginal->EndEnumeration();
for (i = 0; i < arrDelete.Size(); i++)
{
pOriginal->Delete(arrDelete.GetAt(i));
}
arrDelete.Empty();
return hres;
}
//***************************************************************************
//
// CWbemNamespace::Exec_DeleteClass
//
// Actually deletes the class from the database. No class provider support.
// Raises class deletion event.
//
// Parameters and return values are exacly the same as those for DeleteClass
// as described in help
//
//***************************************************************************
HRESULT CWbemNamespace::Exec_DeleteClass(
LPWSTR pszClassName,
long lFlags,
IWbemContext* pCtx,
CBasicObjectSink* pSink
)
{
TIMETRACE(TimeTraces::DeleteClass);
HRESULT hRes;
IWbemServices *pClassProv = 0;
CSynchronousSink* pSyncSink = 0;
BSTR bstrClass = 0;
IWbemClassObject* pStaticClassDef = 0;
BOOL bInRepository = FALSE;
if (pszClassName == 0 || pSink == 0)
return pSink->Return(WBEM_E_INVALID_PARAMETER);
if (pszClassName[0] == L'_')
return pSink->Return(WBEM_E_INVALID_OPERATION);
// Bring up the dynamic class provider symposium for consultation.
// ===============================================================
if (!m_bRepositOnly && m_pProvFact)
{
hRes = m_pProvFact->GetClassProvider(
0, // lFlags
pCtx,
m_wszUserName,
m_wsLocale,
m_pThisNamespace, // IWbemPath pointer
0,
IID_IWbemServices,
(LPVOID *) &pClassProv
);
if (FAILED(hRes))
return pSink->Return(hRes);
}
CReleaseMe _2(pClassProv);
_IWmiCoreWriteHook *pHook = 0;
hRes = m_pCoreSvc->NewPerTaskHook(&pHook);
if (FAILED(hRes))
return pSink->Return(hRes);
CReleaseMe _(pHook);
HRESULT hHookResult = 0;
// First, try repository.
// ======================
if (m_bRepositOnly || m_pProvFact == NULL)
{
if (!Allowed(WBEM_FULL_WRITE_REP))
return pSink->Return(WBEM_E_ACCESS_DENIED);
if (pHook)
pHook->PreDelete(WBEM_FLAG_CLASS_DELETE, lFlags, pCtx, NULL,
m_pThisNamespace, pszClassName );
hRes = CRepository::DeleteByPath(m_pSession, m_pNsHandle, pszClassName, lFlags);
if (pHook)
pHook->PostDelete(WBEM_FLAG_CLASS_DELETE, hRes, pCtx, NULL, m_pThisNamespace, pszClassName, NULL);
return pSink->Return(hRes);
}
// If here, we have to get it first because dynamic class providers
// could be seriously affected by the removal of the class.
// ================================================================
hRes = CRepository::GetObject(
m_pSession,
m_pNsHandle,
pszClassName,
0,
&pStaticClassDef
);
CReleaseMe _1(pStaticClassDef);
if (SUCCEEDED(hRes))
{
bInRepository = TRUE;
if (!Allowed(WBEM_FULL_WRITE_REP))
return pSink->Return(WBEM_E_ACCESS_DENIED);
if (pStaticClassDef == 0)
return pSink->Return(WBEM_E_CRITICAL_ERROR);
}
// Build up a synchronous sink to receive the class.
// =================================================
pSyncSink = CSynchronousSink::Create();
if (pSyncSink == NULL)
return pSink->Return(WBEM_E_OUT_OF_MEMORY);
pSyncSink->AddRef();
CReleaseMe _3(pSyncSink);
// Try to get it.
// ==============
bstrClass = SysAllocString(pszClassName);
if (bstrClass == 0)
return pSink->Return(WBEM_E_OUT_OF_MEMORY);
CSysFreeMe sfm(bstrClass);
// If the class was in the repository, we are merely advising dynamic
// class providers that the class is going away.
// ==================================================================
if (bInRepository)
lFlags |= WBEM_FLAG_ADVISORY;
else
{
if (!Allowed(WBEM_WRITE_PROVIDER))
return pSink->Return(WBEM_E_ACCESS_DENIED);
}
hRes = pClassProv->DeleteClassAsync(bstrClass, lFlags & ~WBEM_FLAG_USE_AMENDED_QUALIFIERS, pCtx, pSyncSink);
if (FAILED(hRes) && hRes != WBEM_E_NOT_FOUND)
return pSink->Return(hRes);
pSyncSink->Block();
IWbemClassObject* pErrorObj = 0;
pSyncSink->GetStatus(&hRes, NULL, &pErrorObj);
CReleaseMe rmErrObj(pErrorObj);
if (FAILED(hRes))
{
pSink->Return(hRes, pErrorObj);
return hRes;
}
// If here, we can go ahead with it.
// =================================
if (pHook)
pHook->PreDelete(WBEM_FLAG_CLASS_DELETE, lFlags, pCtx, NULL,
m_pThisNamespace, pszClassName );
if (bInRepository)
hRes = CRepository::DeleteByPath(m_pSession, m_pNsHandle, pszClassName, lFlags);
if (pHook)
pHook->PostDelete(WBEM_FLAG_CLASS_DELETE, hRes, pCtx, NULL, m_pThisNamespace, pszClassName, NULL);
return pSink->Return(hRes);
}
//***************************************************************************
//
// CWbemNamespace::Exec_CreateClassEnum
//
//***************************************************************************
HRESULT CWbemNamespace::Exec_CreateClassEnum(
LPWSTR pszSuperclass,
long lFlags,
IWbemContext* pCtx,
CBasicObjectSink* pSink
)
{
TIMETRACE(TimeTraces::CreateClassEnum);
HRESULT hRes;
IWbemClassObject* pErrorObj = 0;
IWbemServices *pClassProv = 0;
CSynchronousSink* pSyncSink = 0;
BSTR bstrClass = 0;
IWbemClassObject* pResultObj = 0;
CCombiningSink* pCombiningSink = NULL;
CLocaleMergingSink * pLocaleSink = NULL;
CBasicObjectSink *pTmp = 0;
BSTR bstrSuperclass = 0;
bool bProvSSNotFound = false;
bool bRepNotFound = false;
// Quick check of parms.
// =====================
if (pSink == 0)
return WBEM_E_INVALID_PARAMETER;
if (pszSuperclass == 0) // Ensure we point to a blank instead of NULL with no superclass
pszSuperclass = L"";
else
{
if (illFormatedClass2 (pszSuperclass))
return pSink->Return(WBEM_E_INVALID_CLASS);
}
// Prepare some sinks to hold everything.
// ======================================
if ((lFlags & WBEM_FLAG_USE_AMENDED_QUALIFIERS))
{
pLocaleSink = new CLocaleMergingSink(pSink, m_wsLocale, m_pThisNamespace);
if (pLocaleSink == NULL)
return pSink->Return(WBEM_E_OUT_OF_MEMORY);
pLocaleSink->AddRef();
pTmp = pLocaleSink;
}
else
pTmp = pSink;
CReleaseMe _1(pLocaleSink);
pCombiningSink = new CCombiningSink(pTmp);
if (NULL == pCombiningSink) return pSink->Return(WBEM_E_OUT_OF_MEMORY);
pCombiningSink->AddRef();
CReleaseMe _2(pCombiningSink);
// Bring up the dynamic class provider symposium for consultation.
// ===============================================================
if ( !m_bRepositOnly && m_pProvFact)
{
hRes = m_pProvFact->GetClassProvider(
0, // lFlags
pCtx,
m_wszUserName,
m_wsLocale,
m_pThisNamespace, // IWbemPath pointer
0,
IID_IWbemServices,
(LPVOID *) &pClassProv
);
if (FAILED(hRes))
return pCombiningSink->Return(hRes);
}
CReleaseMe _3(pClassProv);
// Get the repository classes.
// ===========================
BOOL bUseStatic = !(lFlags & WBEM_FLAG_NO_STATIC);
if (bUseStatic)
{
if ((lFlags & WBEM_MASK_DEPTH) == WBEM_FLAG_DEEP)
{
// DEEP ENUM
// ==========
IWbemObjectSink *pObjSink = (IWbemObjectSink *) pCombiningSink;
hRes = CRepository::QueryClasses(
m_pSession,
m_pNsHandle,
WBEM_FLAG_DEEP | WBEM_FLAG_VALIDATE_CLASS_EXISTENCE,
pszSuperclass,
pObjSink);
}
else
{
// SHALLOW ENUM
// =============
IWbemObjectSink *pObjSink = (IWbemObjectSink *) pCombiningSink;
hRes = CRepository::QueryClasses(
m_pSession,
m_pNsHandle,
WBEM_FLAG_SHALLOW | WBEM_FLAG_VALIDATE_CLASS_EXISTENCE,
pszSuperclass,
pObjSink);
}
//If a SetStatus of INVALID_CLASS was indicated it means there is no static
//class, however we need to continue on with dynamic classes, so we need
//to clear the error.
if ((pCombiningSink->GetHResult() == WBEM_E_NOT_FOUND) || (hRes == WBEM_E_NOT_FOUND))
{
bRepNotFound = true;
pCombiningSink->ClearHResult();
hRes = WBEM_S_NO_ERROR;
}
if (FAILED(hRes))
{
// A real failure. Give up.
// =========================
return pCombiningSink->Return(hRes);
}
}
if (m_bRepositOnly || m_pProvFact == NULL)
return pCombiningSink->Return(WBEM_S_NO_ERROR);
// If here, we have to merge in the dynamic classes.
// =================================================
// Build up a synchronous sink to receive the classes.
// ===================================================
pSyncSink = CSynchronousSink::Create();
if (pSyncSink == NULL) return pSink->Return(WBEM_E_OUT_OF_MEMORY);
pSyncSink->AddRef();
CReleaseMe _4(pSyncSink);
// Try to get it.
// ==============
bstrSuperclass = SysAllocString(pszSuperclass);
if (bstrSuperclass == 0)
return pSink->Return(WBEM_E_OUT_OF_MEMORY);
CSysFreeMe sfm99(bstrSuperclass);
CDecoratingSink * pDecore = new CDecoratingSink(pSyncSink, this);
if(pDecore == NULL)
return pSink->Return(WBEM_E_OUT_OF_MEMORY);
pDecore->AddRef();
CReleaseMe cdecor(pDecore);
hRes = pClassProv->CreateClassEnumAsync(bstrSuperclass, (lFlags & (~WBEM_FLAG_USE_AMENDED_QUALIFIERS)) & ~WBEM_FLAG_NO_STATIC, pCtx, pDecore);
if ((pSyncSink->GetHResult() == WBEM_E_NOT_FOUND) || (hRes == WBEM_E_NOT_FOUND))
{
bProvSSNotFound = true;
pSyncSink->ClearHResult();
hRes = WBEM_S_NO_ERROR;
}
if (bProvSSNotFound && bRepNotFound)
{
//Neither the provider subsystem nor the repository found this object,
//therefore we need to actually return an error!
return pCombiningSink->Return(WBEM_E_INVALID_CLASS);
}
if (FAILED(hRes) && hRes != WBEM_E_NOT_FOUND)
return pCombiningSink->Return(hRes);
pSyncSink->Block();
pSyncSink->GetStatus(&hRes, NULL, &pErrorObj);
if (FAILED(hRes))
{
pCombiningSink->Return(hRes, pErrorObj);
if (pErrorObj)
pErrorObj->Release();
return hRes;
}
// Otherwise, somebody claimed to have supplied some classes. Add them into to the
// combining sink.
// =================================================================================
CRefedPointerArray<IWbemClassObject>& raObjects = pSyncSink->GetObjects();
for (int i = 0; i < raObjects.GetSize(); i++)
{
IWbemClassObject *pClsDef = (IWbemClassObject *) raObjects[i];
pCombiningSink->Indicate(1, &pClsDef);
}
return pCombiningSink->Return(WBEM_S_NO_ERROR);
}
//***************************************************************************
//
// CWbemNamespace::Exec_PutClass
//
//***************************************************************************
HRESULT CWbemNamespace::Exec_PutClass(
READONLY IWbemClassObject* pObj,
long lFlags,
IWbemContext* pCtx,
CBasicObjectSink* pSink,
BOOL fIsInternal
)
{
TIMETRACE(TimeTraces::PutClass);
HRESULT hRes;
IWbemClassObject* pErrorObj = 0;
IWbemServices *pClassProv = 0;
CSynchronousSink* pSyncSink = 0;
BSTR bstrClass = 0;
IWbemClassObject* pStaticClassDef = 0;
BOOL bInRepository = FALSE;
// Maintains old functionality
long lRealFlags = lFlags;
if (pSink == 0)
return WBEM_E_INVALID_PARAMETER;
if (pObj == 0) return pSink->Return(WBEM_E_INVALID_PARAMETER);
// Extract the class name.
// =======================
CVARIANT v;
hRes = pObj->Get(L"__CLASS", 0, &v, 0, 0);
if (FAILED(hRes)) return pSink->Return(hRes);
WCHAR * pClassName = L"";
if (VT_BSTR == V_VT(&v) && NULL != V_BSTR(&v))
{
pClassName = V_BSTR(&v);
}
if (wcslen_max(pClassName,g_IdentifierLimit) > g_IdentifierLimit)
return pSink->Return(WBEM_E_QUOTA_VIOLATION);
COperationError OpInfo(pSink, L"PutClass",pClassName);
if (!OpInfo.IsOk()) return pSink->Return(WBEM_E_OUT_OF_MEMORY);
_IWmiObject * pIntObj = NULL;
hRes = pObj->QueryInterface(IID__IWmiObject,(void **)&pIntObj);
CReleaseMe rm1(pIntObj);
if (FAILED(hRes)) return OpInfo.ErrorOccurred(WBEM_E_INVALID_PARAMETER);
if (WBEM_S_NO_ERROR == pIntObj->IsObjectInstance())
return OpInfo.ErrorOccurred(WBEM_E_INVALID_OPERATION);
CVARIANT v2;
hRes = pObj->Get(L"__SuperClass", 0, &v2, 0, 0);
if (FAILED(hRes))
return OpInfo.ErrorOccurred(hRes);
if (v2.GetStr() && wcslen(v2.GetStr())) // SEC:REVIEWED 2002-03-22 : OK; NULL terminator provably exists
{
if (CSystemProperties::IsIllegalDerivedClass(v2.GetStr()))
return OpInfo.ErrorOccurred(WBEM_E_INVALID_SUPERCLASS);
}
if (!fIsInternal )
{
if ((v.GetStr() == NULL) || (v.GetStr()[0] == '_')) // SEC:REVIEWED 2002-03-22 : OK; null terminator provably exists
return OpInfo.ErrorOccurred(WBEM_E_INVALID_OPERATION);
if (v.GetStr()[wcslen(v.GetStr())-1] == '_') // SEC:REVIEWED 2002-03-22 : OK; null terminator provably exists
return OpInfo.ErrorOccurred(WBEM_E_INVALID_OBJECT);
}
if ( !m_bRepositOnly && !fIsInternal && m_pProvFact )
{
// Bring up the dynamic class provider symposium for consultation.
// ===============================================================
hRes = m_pProvFact->GetClassProvider(
0, // lFlags
pCtx,
m_wszUserName,
m_wsLocale,
m_pThisNamespace, // IWbemPath pointer
0,
IID_IWbemServices,
(LPVOID *) &pClassProv
);
if (FAILED(hRes))
return OpInfo.ErrorOccurred(hRes);
}
CReleaseMe _2(pClassProv);
// Set up a new per-task hook.
// ===========================
_IWmiCoreWriteHook *pHook = 0;
hRes = m_pCoreSvc->NewPerTaskHook(&pHook);
if (FAILED(hRes)) return OpInfo.ErrorOccurred(hRes);
CReleaseMe _(pHook);
HRESULT hHookResult = 0;
// First, try repository.
// ======================
if (m_bRepositOnly || fIsInternal || m_pProvFact == NULL)
{
if (!Allowed(WBEM_FULL_WRITE_REP))
return OpInfo.ErrorOccurred(WBEM_E_ACCESS_DENIED);
if (pHook)
pHook->PrePut(WBEM_FLAG_CLASS_PUT, lFlags, pCtx, 0,
m_pThisNamespace, v.GetStr(), (_IWmiObject *)pObj);
hRes = CRepository::PutObject(m_pSession, m_pNsHandle, IID_IWbemClassObject, pObj, lFlags);
if (pHook)
pHook->PostPut(WBEM_FLAG_CLASS_PUT, hRes, pCtx, 0, m_pThisNamespace, v.GetStr() , (_IWmiObject *)pObj, NULL);
return OpInfo.ErrorOccurred(hRes);
}
hRes = CRepository::GetObject(
m_pSession,
m_pNsHandle,
v.GetStr(),
0,
&pStaticClassDef
);
CReleaseMe _1(pStaticClassDef);
if (SUCCEEDED(hRes))
{
bInRepository = TRUE;
if (pStaticClassDef != 0)
{
// Remove all the amended qualifiers
// =================================
if (lFlags & WBEM_FLAG_USE_AMENDED_QUALIFIERS )
{
int nRes = SplitLocalized( (CWbemObject*) pObj, (CWbemObject*) pStaticClassDef );
if (FAILED(nRes))
{
return pSink->Return(nRes);
}
}
}
else
{
return OpInfo.ErrorOccurred(WBEM_E_CRITICAL_ERROR);
}
}
// Build up a synchronous sink to receive the class.
// =================================================
pSyncSink = CSynchronousSink::Create();
if (pSyncSink == NULL) return OpInfo.ErrorOccurred(WBEM_E_OUT_OF_MEMORY);
pSyncSink->AddRef();
CReleaseMe _3(pSyncSink);
// Try to put it.
// ==============
// If the class was in the repository, we are merely advising dynamic
// class providers that the class is going away.
// ==================================================================
if (bInRepository)
lFlags |= WBEM_FLAG_ADVISORY;
if (!Allowed(WBEM_WRITE_PROVIDER))
hRes = WBEM_E_ACCESS_DENIED;
else
hRes = pClassProv->PutClassAsync(pObj, lFlags & ~WBEM_FLAG_USE_AMENDED_QUALIFIERS, pCtx, pSyncSink);
if (FAILED(hRes) && hRes != WBEM_E_NOT_FOUND)
return OpInfo.ErrorOccurred(hRes);
pSyncSink->Block();
pSyncSink->GetStatus(&hRes, NULL, &pErrorObj);
if (SUCCEEDED(hRes)&&(!bInRepository))
{
pSink->Return(hRes, pErrorObj);
if (pErrorObj)
pErrorObj->Release();
return hRes;
}
if (FAILED(hRes) && hRes != WBEM_E_NOT_FOUND)
{
pSink->Return(hRes, pErrorObj);
if (pErrorObj)
pErrorObj->Release();
return hRes;
}
// If here, we can go ahead with it.
// =================================
if (!Allowed(WBEM_FULL_WRITE_REP))
return OpInfo.ErrorOccurred(WBEM_E_ACCESS_DENIED);
if (pHook)
{
pHook->PrePut(WBEM_FLAG_CLASS_PUT, lFlags, pCtx, 0,
m_pThisNamespace, v.GetStr(), (_IWmiObject *)pObj);
}
hRes = CRepository::PutObject(m_pSession, m_pNsHandle, IID_IWbemClassObject, pObj, lFlags);
// Workaround for forceupdate and instances problem
if ( WBEM_E_CLASS_HAS_INSTANCES == hRes && ( lRealFlags & WBEM_FLAG_UPDATE_FORCE_MODE ) )
{
_variant_t v;
hRes = pObj->Get( L"__CLASS", 0L, &v, NULL, NULL );
if ( SUCCEEDED( hRes ) && V_VT( &v ) == VT_BSTR )
{
hRes = DeleteObject( V_BSTR( &v ), 0L, pCtx, NULL );
if ( SUCCEEDED( hRes ) )
{
hRes = CRepository::PutObject(m_pSession, m_pNsHandle, IID_IWbemClassObject, pObj, lFlags);
}
}
else
{
hRes = WBEM_E_CLASS_HAS_INSTANCES;
}
}
if (pHook)
{
pHook->PostPut(WBEM_FLAG_CLASS_PUT, hRes, pCtx, 0, m_pThisNamespace, v.GetStr() , (_IWmiObject *)pObj, NULL);
}
return OpInfo.ErrorOccurred(hRes);
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWbemNamespace::Exec_CancelAsyncCall(
IWbemObjectSink* pSink
)
{
_IWmiArbitrator *pArb = CWmiArbitrator::GetUnrefedArbitrator();
HRESULT hRes = pArb->CancelTasksBySink(0, IID_IWbemObjectSink, pSink);
return hRes;
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWbemNamespace::Exec_CancelProvAsyncCall(
IWbemServices* pProv, IWbemObjectSink* pSink
)
{
// Call to the actual provider
HRESULT hRes = pProv->CancelAsyncCall( pSink );
return hRes;
}
//***************************************************************************
//
// CWbemNamespace::Exec_PutInstance
//
// Actually stores the instance in the database. If the class is dynamic, the
// call is propagated to the provider.
// Raises instance creation or modification event.
//
// Parameters and return values are exacly the same as those for PutInstance
// as described in help
//
//***************************************************************************
HRESULT CWbemNamespace::Exec_PutInstance(
IWbemClassObject* pInst,
long lFlags,
IWbemContext* pCtx,
CBasicObjectSink* pSink
)
{
TIMETRACE(TimeTraces::PutInstance);
HRESULT hRes = CheckNs();
if (FAILED(hRes)) return hRes;
if (NULL == pSink) return WBEM_E_INVALID_PARAMETER;
if(pInst == NULL) return pSink->Return(WBEM_E_INVALID_PARAMETER);
COperationError OpInfo(pSink, L"PutInstance", L"");
if (!OpInfo.IsOk()) return pSink->Return(WBEM_E_OUT_OF_MEMORY);
CWbemObject *pObj = (CWbemObject *) pInst;
HRESULT hres;
_variant_t v;
hRes = pObj->Get(L"__RELPATH", 0, &v, NULL, NULL);
if (FAILED(hRes)) return OpInfo.ErrorOccurred(hRes);
if(VT_BSTR == V_VT(&v))
{
if (wcslen_max(V_BSTR(&v),g_PathLimit) > g_PathLimit)
return OpInfo.ErrorOccurred(WBEM_E_QUOTA_VIOLATION);
}
if (!pObj->IsInstance())
return OpInfo.ErrorOccurred(WBEM_E_INVALID_OBJECT);
if (!pObj->IsKeyed())
return OpInfo.ErrorOccurred(WBEM_E_NO_KEY);
if (pObj->IsLimited())
return OpInfo.ErrorOccurred(WBEM_E_INVALID_OBJECT);
if (pObj->IsClientOnly())
return OpInfo.ErrorOccurred(WBEM_E_INVALID_OBJECT);
// Check if localization bits are set, and if so, that the
// AMENDED_QUALIFIERS flag was specified.
if ( ((CWbemObject*) pObj)->IsLocalized() &&
!( lFlags & WBEM_FLAG_USE_AMENDED_QUALIFIERS ) )
{
return OpInfo.ErrorOccurred( WBEM_E_AMENDED_OBJECT );
}
if((lFlags & WBEM_FLAG_UPDATE_ONLY) == 0)
{
// Make sure that put extensions are not used without UPDATE_ONLY
// ==============================================================
BOOL bExtended;
hres = GetContextBoolean(pCtx, L"__PUT_EXTENSIONS", &bExtended);
if(FAILED(hres) || bExtended)
return OpInfo.ErrorOccurred(WBEM_E_INVALID_CONTEXT);
}
BSTR strPropName = NULL;
CSysFreeMeRef fmref(strPropName);
if(!pObj->ValidateRange(&strPropName))
{
OpInfo.SetParameterInfo(strPropName); // throws
return OpInfo.ErrorOccurred(WBEM_E_INVALID_PROPERTY);
}
// Build the key string.
// =====================
CVar vClass;
hres = pObj->GetClassName(&vClass); // throw
if (FAILED(hres))
return OpInfo.ErrorOccurred(WBEM_E_INVALID_OBJECT);
OpInfo.SetParameterInfo(vClass.GetLPWSTR()); // throws
// Get the class definition
// ========================
IWbemClassObject* pErrorObj = NULL;
IWbemClassObject* pClassObj = NULL;
hres = Exec_GetObjectByPath(vClass.GetLPWSTR(), 0, pCtx,&pClassObj, &pErrorObj);
CReleaseMe rmErrObj(pErrorObj);
CReleaseMe rm1(pClassObj);
if(hres == WBEM_E_NOT_FOUND) hres = WBEM_E_INVALID_CLASS;
if(FAILED(hres)) return OpInfo.ErrorOccurred(hres, pErrorObj);
CWbemClass *pClassDef = (CWbemClass*)pClassObj;
// Dont allow write of old security classes. This prevents
// a nefarious user from trying to slip in some extra rights
if (wbem_wcsicmp(vClass.GetLPWSTR(), L"__NTLMUser") == 0 ||
wbem_wcsicmp(vClass.GetLPWSTR(), L"__NTLMGroup") == 0)
{
if (!Allowed(WRITE_DAC))
return OpInfo.ErrorOccurred(WBEM_E_ACCESS_DENIED);
if((lFlags & WBEM_FLAG_ONLY_STATIC) == 0)
{
return PutSecurityClassInstances(vClass.GetLPWSTR(), pInst ,
pSink, pCtx, lFlags);
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Dont allow write on the __thisnamespace instance -- except during an upgrade in setup
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if (wbem_wcsicmp(vClass.GetLPWSTR(), L"__thisnamespace") == 0 && !IsNtSetupRunning())
{
return OpInfo.ErrorOccurred(WBEM_E_INVALID_OPERATION);
}
// Make sure that the instance and the class match
// ===============================================
// SJS - Amendment is the same as Abstract
if( pClassDef->IsAmendment() || pClassDef->IsAbstract() || !pClassDef->IsKeyed() )
{
return OpInfo.ErrorOccurred(WBEM_E_INVALID_OPERATION);
}
if(!((CWbemInstance*)pObj)->IsInstanceOf(pClassDef)) // trow
{
return OpInfo.ErrorOccurred(WBEM_E_INVALID_CLASS);
}
// Verify provider validity
// ========================
// Only administrators can change provider registration
// RAID# 566241
// ==================================
if(pObj->InheritsFrom(L"__Provider") == S_OK || pObj->InheritsFrom(L"__ProviderRegistration") == S_OK)
{
HANDLE hAccess;
hres = GetAccessToken(hAccess);
if ( FAILED (hres) )
{
if ( hres != 0x80041007 )
{
return OpInfo.ErrorOccurred(WBEM_E_ACCESS_DENIED);
}
}
else
{
if ( !IsAdmin(hAccess))
{
CloseHandle ( hAccess );
return OpInfo.ErrorOccurred(WBEM_E_ACCESS_DENIED);
}
CloseHandle ( hAccess );
}
}
// While the class may not be dynamically provided, some of the
// properties might be.
// ============================================================
hres = GetOrPutDynProps(pObj, PUT, pClassDef->IsDynamic());
if(FAILED(hres))
{
ERRORTRACE((LOG_WBEMCORE, "Failed to pre-process an instance of %S using "
"a property provider. Error code: %X\n",
vClass.GetLPWSTR(), hres));
}
// Recursively Put in all the right places
// ======================================
CCombiningSink* pCombSink = new CCombiningSink(OpInfo.GetSink());
if(pCombSink == NULL)
return OpInfo.ErrorOccurred(WBEM_E_OUT_OF_MEMORY);
pCombSink->AddRef();
CReleaseMe rm2(pCombSink);
return RecursivePutInstance((CWbemInstance*)pObj, pClassDef, lFlags,
pCtx, pCombSink, TRUE);
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWbemNamespace::RecursivePutInstance(
CWbemInstance* pInst,
CWbemClass* pClassDef,
long lFlags,
IWbemContext* pCtx,
CBasicObjectSink* pSink,
BOOL bLast
)
{
HRESULT hRes;
// See if any action is required at this level
// ===========================================
if (pClassDef->IsAbstract() || pClassDef->IsAmendment() || !pClassDef->IsKeyed())
return WBEM_S_FALSE;
// See if we need to go up
// =======================
BOOL bParentTookCareOfItself = TRUE;
if (pClassDef->IsDynamic())
{
// Get the parent class
// ====================
CVar vParentName;
pClassDef->GetSuperclassName(&vParentName);
if (!vParentName.IsNull())
{
IWbemClassObject* pParentClass = NULL;
IWbemClassObject* pErrorObj = NULL;
hRes = Exec_GetObjectByPath(vParentName.GetLPWSTR(), 0, pCtx,&pParentClass, &pErrorObj);
CReleaseMe rm1(pParentClass);
CReleaseMe rm2(pErrorObj);
if (FAILED(hRes))
{
pSink->Return(hRes, pErrorObj);
return hRes;
}
// Get it to put it's portion
// ==========================
hRes = RecursivePutInstance(pInst, (CWbemClass*)pParentClass,lFlags, pCtx, pSink, FALSE);
if(FAILED(hRes))
return hRes;
if(hRes == WBEM_S_FALSE)
bParentTookCareOfItself = FALSE;
}
}
// Parent Puts have been taken care of. Call it on our own class.
// ==============================================================
// Convert the instance to the right class
// =======================================
CWbemInstance* pNewInst = NULL;
pInst->ConvertToClass(pClassDef, &pNewInst);
CReleaseMe rm1((IWbemClassObject*)pNewInst);
if (pNewInst == NULL)
{
ERRORTRACE((LOG_WBEMCORE, "Failed to convert an instance to a base class\n"));
return pSink->Return(WBEM_E_CRITICAL_ERROR);
}
if (pClassDef->IsDynamic())
{
// Check if we need to do a put at this level
// ==========================================
if (!bLast && (lFlags & WBEM_FLAG_UPDATE_ONLY))
{
hRes = IsPutRequiredForClass(pClassDef, pInst, pCtx, bParentTookCareOfItself);
if (FAILED(hRes))
return pSink->Return(hRes);
if (hRes == WBEM_S_FALSE)
{
// No need to put this class
// =========================
return pSink->Return(WBEM_S_NO_ERROR);
}
}
// Get the provider name.
// ======================
CVar vProv;
hRes = pClassDef->GetQualifier(L"Provider", &vProv);
if (FAILED(hRes) || vProv.GetType() != VT_BSTR)
{
return pSink->Return(WBEM_E_INVALID_PROVIDER_REGISTRATION);
}
// Access the provider cache. First check permission
// ==================================================
if (!Allowed(WBEM_WRITE_PROVIDER))
return pSink->Return(WBEM_E_ACCESS_DENIED);
CSynchronousSink* pSyncSink = CSynchronousSink::Create(pSink);
if(pSyncSink == NULL) return pSink->Return(WBEM_E_OUT_OF_MEMORY);
pSyncSink->AddRef();
CReleaseMe rmSync(pSyncSink);
IWbemServices *pProv = 0;
if(m_pProvFact == NULL) return pSink->Return(WBEM_E_CRITICAL_ERROR);
WmiInternalContext t_InternalContext ;
ZeroMemory ( & t_InternalContext , sizeof ( t_InternalContext ) ) ; // SEC:REVIEWED 2002-03-22 : OK
hRes = m_pProvFact->GetProvider(
t_InternalContext ,
0, // lFlags
pCtx,
0,
m_wszUserName,
m_wsLocale,
0, // IWbemPath pointer
vProv, // Provider
IID_IWbemServices,
(LPVOID *) &pProv
);
if (FAILED(hRes)) return pSink->Return(hRes);
CReleaseMe _(pProv);
pProv->PutInstanceAsync(pNewInst, lFlags& ~WBEM_FLAG_USE_AMENDED_QUALIFIERS, pCtx, pSyncSink);
pSyncSink->Block();
IWbemClassObject* pErrorObj = NULL;
BSTR str;
pSyncSink->GetStatus(&hRes, &str, &pErrorObj);
CSysFreeMe sfm(str);
CReleaseMe rmErrObj(pErrorObj);
rmSync.release();
// It is ok if the upper levels report "provider not capable".
// ===========================================================
if (!bLast && hRes == WBEM_E_PROVIDER_NOT_CAPABLE)
hRes = 0;
if (FAILED(hRes))
{
COperationError OpInfo(pSink, L"PutInstance", L"");
if (!OpInfo.IsOk()) return WBEM_E_OUT_OF_MEMORY;
OpInfo.ProviderReturned(vProv.GetLPWSTR(), hRes, pErrorObj);
return hRes;
}
else if (str)
{
pSink->SetStatus(0, hRes, str, NULL);
}
// Provider passes back NULL, we should construct the instance path and return to client
// NT RAID: 186286 [marioh]
// ======================================================================================
else
{
BSTR str = NULL;
LPWSTR wszPath = pNewInst->GetRelPath();
if (wszPath )
{
str = SysAllocString(wszPath);
delete [] wszPath;
}
pSink->SetStatus(0, hRes, str, NULL);
SysFreeString(str);
}
return WBEM_S_NO_ERROR;
}
// The class is not dynamically provided.
// ======================================
hRes = ((CWbemInstance*)pNewInst)->PlugKeyHoles();
if (FAILED(hRes))
return pSink->Return(hRes);
// Get the path.
// =============
CVar vClass;
hRes = pNewInst->GetClassName(&vClass);
if (FAILED(hRes))
return pSink->Return(WBEM_E_OUT_OF_MEMORY);
WCHAR * ClassNameStr = vClass.GetLPWSTR();
// Check permissions for writes on system classes.
// ===============================================
bool derivedFromSys = false;
HRESULT hr = IsDerivedFromSystem(*pNewInst, &derivedFromSys);
if (FAILED(hr)) return pSink->Return(hr);
if (derivedFromSys)
{
if (!Allowed(WBEM_FULL_WRITE_REP))
return pSink->Return(WBEM_E_ACCESS_DENIED);
}
else if (!Allowed(WBEM_PARTIAL_WRITE_REP))
{
return pSink->Return(WBEM_E_ACCESS_DENIED);
}
CVARIANT v;
hRes = pNewInst->Get(L"__RELPATH", 0, &v, 0, 0);
if(FAILED(hRes))
return pSink->Return(hRes);
if(v.GetType() != VT_BSTR)
return pSink->Return(WBEM_E_CRITICAL_ERROR);
// Set up a new per-task hook.
// ===========================
_IWmiCoreWriteHook *pHook = 0;
hRes = m_pCoreSvc->NewPerTaskHook(&pHook);
if (FAILED(hRes))
return pSink->Return(hRes);
CReleaseMe _(pHook);
HRESULT hHookResult = 0;
// See if the instance already exists.
// ===================================
IWbemClassObject *pExistingObject = 0;
hRes = CRepository::GetObject(m_pSession, m_pScopeHandle, v.GetStr(),0, &pExistingObject);
CReleaseMe _2(pExistingObject);
if (FAILED(hRes))
{
// If we here, we failed to get it from the repository. Thus, it needs to be created from scratch.
// ================================================================================================
// Remove all the amended qualifiers
// =================================
if (lFlags & WBEM_FLAG_USE_AMENDED_QUALIFIERS )
{
int nRes = SplitLocalized(pNewInst);
if (FAILED(nRes))
return pSink->Return(nRes);
}
if((lFlags & WBEM_MASK_CREATE_UPDATE) == WBEM_FLAG_UPDATE_ONLY)
{
return pSink->Return(WBEM_E_NOT_FOUND);
}
// As a special case, see if the object is
// of class <__NAMESPACE>. If so, create a new namespace
// for it.
// ======================================================
if ((wbem_wcsicmp(vClass.GetLPWSTR(), L"__NAMESPACE") == 0) ||
(CRepository::InheritsFrom(m_pSession, m_pNsHandle, L"__NAMESPACE", vClass.GetLPWSTR()) == 0))
{
hRes = CreateNamespace(pNewInst);
if (FAILED(hRes))
return pSink->Return(hRes);
}
// Not a __NAMESPACE or derivative.
// ================================
else
{
// If here, the object didn't already exist in the repository, so we
// can add it to the database.
// ==================================================================
// Check if this instance makes any sense to
// hook callbacks.
// =========================================
hRes = DecorateObject(pNewInst);
if (FAILED(hRes))
return pSink->Return(hRes);
IWbemClassObject* pInstObj = pNewInst;
IWbemClassObject* pOldObj = 0;
if (pHook)
{
// If there are hooks, try them and note whether callback is required.
// ===================================================================
hHookResult = pHook->PrePut(WBEM_FLAG_INST_PUT, lFlags, pCtx, 0,
m_pThisNamespace, ClassNameStr, pNewInst
);
}
if (FAILED(hHookResult))
{
return pSink->Return(hHookResult);
}
if (hHookResult == WBEM_S_POSTHOOK_WITH_BOTH)
{
CRepository::GetObject(m_pSession, m_pNsHandle, v.GetStr(), 0, &pOldObj);
}
// Actually create it in the database
// ==================================
hRes = CRepository::PutObject(m_pSession, m_pScopeHandle, IID_IWbemClassObject, LPVOID(pNewInst), DWORD(lFlags));
if (pHook)
pHook->PostPut(WBEM_FLAG_INST_PUT, hRes, pCtx, 0, m_pThisNamespace, ClassNameStr, pNewInst, (_IWmiObject *) pOldObj);
delete pOldObj;
if (FAILED(hRes))
{
return pSink->Return(hRes);
}
}
}
// If here, the object was already in the repository and requires updating.
// ========================================================================
else
{
if((lFlags & WBEM_MASK_CREATE_UPDATE) == WBEM_FLAG_CREATE_ONLY)
{
return pSink->Return(WBEM_E_ALREADY_EXISTS);
}
// Remove all the amended qualifiers
// =================================
if (lFlags & WBEM_FLAG_USE_AMENDED_QUALIFIERS )
{
int nRes = SplitLocalized(pNewInst, (CWbemObject *) pExistingObject);
if (FAILED(nRes))
{
return pSink->Return(nRes);
}
}
// Check if this update makes any sense to the ESS
// ===============================================
hRes = DecorateObject(pNewInst);
if (FAILED(hRes))
return pSink->Return(hRes);
IWbemClassObject* pInstObj = pNewInst;
// Check pre-hook.
// ===============
if (pHook)
{
// If there are hooks, try them and note whether callback is required.
// ===================================================================
hHookResult = pHook->PrePut(WBEM_FLAG_INST_PUT, lFlags, pCtx, 0,
m_pThisNamespace, ClassNameStr, pNewInst
);
}
if (FAILED(hHookResult))
return pSink->Return(hHookResult);
// Actually create it in the database
// ==================================
hRes = CRepository::PutObject(m_pSession, m_pScopeHandle, IID_IWbemClassObject, LPVOID(pNewInst), DWORD(lFlags));
// Post put.
// =========
if (pHook)
pHook->PostPut(WBEM_FLAG_INST_PUT, hRes, pCtx, 0, m_pThisNamespace, ClassNameStr, pNewInst, (_IWmiObject *) pExistingObject);
if (FAILED(hRes))
return pSink->Return(hRes);
}
// Assign appropriate value to the path
// ====================================
LPWSTR wszPath = pNewInst->GetRelPath();
BSTR str = SysAllocString(wszPath);
delete [] wszPath;
pSink->SetStatus(0, WBEM_S_NO_ERROR, str, NULL);
SysFreeString(str);
return WBEM_NO_ERROR;
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWbemNamespace::CreateNamespace(CWbemInstance *pNewInst)
{
//
// internal interface throws
//
CVar vNsName;
HRESULT hRes = pNewInst->GetProperty(L"Name", &vNsName);
if (FAILED(hRes) || vNsName.IsNull())
{
return WBEM_E_INVALID_NAMESPACE;
}
// verify that this name is valid
// ==============================
if (!IsValidElementName(vNsName.GetLPWSTR(),g_PathLimit-NAMESPACE_ADJUSTMENT))
{
return WBEM_E_INVALID_NAMESPACE;
}
if (!Allowed(WBEM_FULL_WRITE_REP))
{
return WBEM_E_ACCESS_DENIED;
}
//Get a new session for transactioning purposes...
IWmiDbSession *pSession = NULL;
IWmiDbSessionEx *pSessionEx = NULL;
hRes = CRepository::GetNewSession(&pSession);
if (FAILED(hRes))
return hRes;
//Get an EX version that supports transactioning...
pSession->QueryInterface(IID_IWmiDbSessionEx, (void**)&pSessionEx);
if (pSessionEx)
{
pSession->Release();
pSession = pSessionEx;
}
CReleaseMe relMe1(pSession);
//If we have transactionable session, use it!
if (pSessionEx)
{
hRes = pSessionEx->BeginWriteTransaction(0);
if (FAILED(hRes))
{
return hRes;
}
}
try
{
// Build the new namespace name.
// =============================
// Create the namespace
// =====================
if (SUCCEEDED(hRes))
hRes = CRepository::PutObject(pSession, m_pScopeHandle, IID_IWbemClassObject, LPVOID(pNewInst), 0);
// Set the default instances.
// ===============================
CWbemNamespace* pNewNs = NULL;
if (SUCCEEDED(hRes))
pNewNs = CWbemNamespace::CreateInstance();
if (SUCCEEDED(hRes) && pNewNs != NULL)
{
int iLen = 2;
if(m_pThisNamespace)
iLen += wcslen(m_pThisNamespace); // SEC:REVIEWED 2002-03-22 : OK; null terminator is there by prior precondition
if(vNsName.GetLPWSTR())
iLen += wcslen(vNsName.GetLPWSTR()); // SEC:REVIEWED 2002-03-22 : OK; provably ok or we couldn't be here
WCHAR * pTemp = new WCHAR[iLen];
if(pTemp)
{
*pTemp = L'\0';
if(m_pThisNamespace)
{
StringCchCopyW(pTemp, iLen, m_pThisNamespace);
StringCchCatW(pTemp, iLen, L"\\");
}
if(vNsName.GetLPWSTR())
StringCchCatW(pTemp, iLen, vNsName.GetLPWSTR());
//Initialize the namespace object
hRes = pNewNs->Initialize(pTemp,GetUserName(), 0, 0, FALSE, TRUE, // SEC:REVIEWED 2002-03-22 : OK
NULL, 0xFFFFFFFF, TRUE, pSession);
delete pTemp;
}
else
{
hRes = WBEM_E_OUT_OF_MEMORY;
}
if(SUCCEEDED(hRes))
{
hRes = CRepository::EnsureNsSystemInstances(pSession, pNewNs->m_pNsHandle, pSession, m_pNsHandle);
}
if (SUCCEEDED(hRes))
hRes = InitializeSD(pSession);
pNewNs->Release();
}
else if (SUCCEEDED(hRes))
{
hRes = WBEM_E_OUT_OF_MEMORY;
}
}
catch (CX_MemoryException &)
{
hRes = WBEM_E_OUT_OF_MEMORY;
}
catch (...)
{
ExceptionCounter c;
ERRORTRACE((LOG_WBEMCORE, "Namespace Creation of <%S> caused a very critical error!\n", vNsName.GetLPWSTR()));
hRes = WBEM_E_CRITICAL_ERROR;
}
if (FAILED(hRes))
{
ERRORTRACE((LOG_WBEMCORE, "Namespace Creation of <%S> caused an error <0x%X>!\n", vNsName.GetLPWSTR(), hRes));
if (pSessionEx)
pSessionEx->AbortTransaction(0);
}
else
{
hRes = DecorateObject(pNewInst);
if (FAILED(hRes))
{
if (pSessionEx)
pSessionEx->AbortTransaction(0);
}
else
{
if (pSessionEx)
{
hRes = pSessionEx->CommitTransaction(0);
}
}
}
return hRes;
}
//***************************************************************************
//
// CWbemNamespace::Exec_DeleteInstance
//
// Actually deletes the instance from the database. No instance provider
// support. Raises instance deletion event.
//
// Parameters and return values are exacly the same as those for DeleteInstance
// as described in help
//
//***************************************************************************
HRESULT CWbemNamespace::Exec_DeleteInstance(
READONLY LPWSTR wszObjectPath,
long lFlags,
IWbemContext* pCtx,
CBasicObjectSink* pSink
)
{
TIMETRACE(TimeTraces::DeleteInstance);
return DeleteSingleInstance(wszObjectPath, lFlags, pCtx, pSink);
}
//***************************************************************************
//
//***************************************************************************
//
HRESULT CWbemNamespace::DeleteSingleInstance(
READONLY LPWSTR wszObjectPath,
long lFlags,
IWbemContext* pCtx,
CBasicObjectSink* pSink
)
{
HRESULT hRes;
int nRes;
COperationError OpInfo(pSink, L"DeleteInstance", wszObjectPath);
if ( !OpInfo.IsOk() ) return WBEM_E_OUT_OF_MEMORY;
// Parse the object path to get the class involved.
// ================================================
ParsedObjectPath* pOutput = 0;
CObjectPathParser p;
int nStatus = p.Parse(wszObjectPath, &pOutput);
OnDeleteObj<ParsedObjectPath*,CObjectPathParser,
void (CObjectPathParser:: *)(ParsedObjectPath *pOutput),
&CObjectPathParser::Free> FreeMe(&p,pOutput);
if (nStatus != 0 || !pOutput->IsInstance())
{
return OpInfo.ErrorOccurred(WBEM_E_INVALID_OBJECT_PATH);
}
// Exception for __WinMgmtIdentification
if (!wbem_wcsicmp(pOutput->m_pClass, L"__CIMOMIdentification") ||
!wbem_wcsicmp(pOutput->m_pClass, L"__SystemSecurity") ||
!wbem_wcsicmp(pOutput->m_pClass, L"__ADAPStatus" ) )
{
return OpInfo.ErrorOccurred(WBEM_E_INVALID_OPERATION);
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Dont allow deletion on the __thisnamespace instance
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if (wbem_wcsicmp(pOutput->m_pClass, L"__thisnamespace") == 0 )
{
return OpInfo.ErrorOccurred(WBEM_E_INVALID_OPERATION);
}
// Special case for the old security classes
// ==========================================
if (wbem_wcsicmp(pOutput->m_pClass, L"__NTLMUser") == 0 ||
wbem_wcsicmp(pOutput->m_pClass, L"__NTLMGroup") == 0)
{
if (!Allowed(WRITE_DAC))
{
return OpInfo.ErrorOccurred(WBEM_E_ACCESS_DENIED);
}
if((lFlags & WBEM_FLAG_ONLY_STATIC) == 0)
{
return DeleteSecurityClassInstances(pOutput, pSink, pCtx,lFlags);
}
}
// As a special case, see if the object is
// of class <__NAMESPACE>. If so, (TEMP) disallow deletion.
// =========================================================
WString wsNamespaceName;
if (wbem_wcsicmp(pOutput->m_pClass, L"__NAMESPACE") == 0 ||
CRepository::InheritsFrom(m_pSession, m_pScopeHandle, L"__NAMESPACE", pOutput->m_pClass) == 0
)
{
if (!Allowed(WBEM_FULL_WRITE_REP))
{
return OpInfo.ErrorOccurred(WBEM_E_ACCESS_DENIED);
}
if (pOutput->m_dwNumKeys != 1)
{
return OpInfo.ErrorOccurred(WBEM_E_INVALID_OBJECT_PATH);
}
KeyRef* pKey = pOutput->m_paKeys[0];
if (pKey->m_pName != NULL && wbem_wcsicmp(pKey->m_pName, L"name"))
{
return OpInfo.ErrorOccurred(WBEM_E_INVALID_OBJECT_PATH);
}
if (V_VT(&pKey->m_vValue) != VT_BSTR)
{
return OpInfo.ErrorOccurred(WBEM_E_INVALID_OBJECT_PATH);
}
// Prevent deletion of standard namespaces.
// ========================================
if (wbem_wcsicmp(m_pThisNamespace, L"ROOT") == 0)
{
BSTR pNs = V_BSTR(&pKey->m_vValue);
if (!pNs)
{
return OpInfo.ErrorOccurred(WBEM_E_INVALID_OBJECT_PATH);
}
if (wbem_wcsicmp(pNs, L"SECURITY") == 0)
{
return OpInfo.ErrorOccurred(WBEM_E_ACCESS_DENIED);
}
if (wbem_wcsicmp(pNs, L"DEFAULT") == 0)
{
return OpInfo.ErrorOccurred(WBEM_E_ACCESS_DENIED);
}
}
// Set up hook.
// ============
_IWmiCoreWriteHook *pHook = 0;
HRESULT hRes = m_pCoreSvc->NewPerTaskHook(&pHook);
CReleaseMe _(pHook);
HRESULT hHookResult = 0;
LPWSTR pszClassName = 0;
IWbemPath *pPath = 0;
CVectorDeleteMe<WCHAR> vdmClassName(&pszClassName);
if (pHook)
{
// Parse the object path.
// ======================
hRes = m_pCoreSvc->CreatePathParser(0, &pPath);
if (FAILED(hRes))
{
return OpInfo.ErrorOccurred(hRes);
}
CReleaseMe _3Path(pPath);
hRes = pPath->SetText(WBEMPATH_CREATE_ACCEPT_ALL, wszObjectPath);
if (FAILED(hRes))
{
return OpInfo.ErrorOccurred(hRes);
}
ULONG uBuf = 0;
hRes = pPath->GetClassName(&uBuf, 0);
if (FAILED(hRes))
{
return OpInfo.ErrorOccurred(hRes);
}
pszClassName = new wchar_t[uBuf+1];
if (pszClassName == 0)
{
return OpInfo.ErrorOccurred(WBEM_E_OUT_OF_MEMORY);
}
hRes = pPath->GetClassName(&uBuf, pszClassName);
if (FAILED(hRes))
{
return OpInfo.ErrorOccurred(hRes);
}
// If there are hooks, try them and note whether callback is required.
// ===================================================================
hHookResult = pHook->PreDelete(WBEM_FLAG_INST_DELETE, lFlags, pCtx, pPath,
m_pThisNamespace, pszClassName);
if (FAILED(hHookResult))
{
return OpInfo.ErrorOccurred(hHookResult);
}
pPath->AddRef();
}
CReleaseMe _2Path(pPath);
// Ensure the object can be reached so that we can delete it.
// ==========================================================
IWbemClassObject *pExistingObject = 0;
hRes = CRepository::GetObject(m_pSession, m_pScopeHandle, wszObjectPath, 0, &pExistingObject);
if (FAILED(hRes))
{
return OpInfo.ErrorOccurred(hRes);
}
CReleaseMe _2(pExistingObject);
if (hRes == WBEM_S_NO_ERROR) // new test
{
// Check if we may
// ===============
if (!Allowed(WBEM_FULL_WRITE_REP))
{
return OpInfo.ErrorOccurred(WBEM_E_ACCESS_DENIED);
}
// Go ahead and try the deletion.
// ==============================
WString sNamespace = "__Namespace='";
sNamespace += V_BSTR(&pKey->m_vValue);
sNamespace += "'";
hRes = CRepository::DeleteByPath(m_pSession, m_pScopeHandle, LPWSTR(sNamespace), 0);
// Call post hook.
// ===============
if (pHook)
pHook->PostDelete(WBEM_FLAG_INST_DELETE, hRes, pCtx, pPath,
m_pThisNamespace, pszClassName, (_IWmiObject *) pExistingObject);
// Decide what to do if things didn't work out.
// ============================================
if (FAILED(hRes))
{
return OpInfo.ErrorOccurred(hRes);
}
}
else
{
return OpInfo.ErrorOccurred(hRes);
}
wsNamespaceName = V_BSTR(&pKey->m_vValue);
return OpInfo.ErrorOccurred(WBEM_S_NO_ERROR);
}
// See if the class is dynamic
// ===========================
CWbemObject *pClassDef = 0;
IWbemClassObject* pErrorObj = NULL;
IWbemClassObject* pClassObj = NULL;
HRESULT hres = Exec_GetObjectByPath(pOutput->m_pClass, 0,
pCtx,&pClassObj, &pErrorObj);
CReleaseMe rmErrObj(pErrorObj);
CReleaseMe rmClsDef(pClassObj);
if(hres == WBEM_E_NOT_FOUND) hres = WBEM_E_INVALID_CLASS;
if(FAILED(hres))
{
OpInfo.ErrorOccurred(hres, pErrorObj);
return WBEM_S_NO_ERROR;
}
pClassDef = (CWbemObject*)pClassObj;
CVar vDynFlag;
hres = pClassDef->GetQualifier(L"Dynamic", &vDynFlag);
if (SUCCEEDED(hres) && vDynFlag.GetType() == VT_BOOL && vDynFlag.GetBool())
{
// Get the provider name.
CVar vProv;
hres = pClassDef->GetQualifier(L"Provider", &vProv);
if (FAILED(hres) || vProv.GetType() != VT_BSTR)
{
return OpInfo.ErrorOccurred(WBEM_E_INVALID_PROVIDER_REGISTRATION);
}
if (!Allowed(WBEM_WRITE_PROVIDER))
return OpInfo.ErrorOccurred(WBEM_E_ACCESS_DENIED);
// Access the provider cache.
// ==========================
IWbemServices *pProv = 0;
HRESULT hRes;
if(m_pProvFact == NULL)
return OpInfo.ErrorOccurred(WBEM_E_CRITICAL_ERROR);
WmiInternalContext t_InternalContext ;
ZeroMemory ( & t_InternalContext , sizeof ( t_InternalContext ) );
hRes = m_pProvFact->GetProvider(t_InternalContext ,
0, // lFlags
pCtx,
0,
m_wszUserName,
m_wsLocale,
0, // IWbemPath pointer
vProv, // Provider
IID_IWbemServices,
(LPVOID *) &pProv);
if (FAILED(hRes))
{
return OpInfo.ErrorOccurred(hRes);
}
CReleaseMe rmProv(pProv);
hRes = pProv->DeleteInstanceAsync( wszObjectPath,
lFlags& ~WBEM_FLAG_USE_AMENDED_QUALIFIERS,
pCtx,
OpInfo.GetSink());
return WBEM_S_NO_ERROR;
}
// The class is not dynamically provided.
// ======================================
// Only administrators can change provider registration
// RAID# 566241
// ==================================
if(pClassDef->InheritsFrom(L"__Provider") == S_OK || pClassDef->InheritsFrom(L"__ProviderRegistration") == S_OK)
{
HANDLE hAccess;
hres = GetAccessToken (hAccess);
if ( FAILED (hres) )
{
if ( hres != 0x80041007 )
{
return OpInfo.ErrorOccurred(WBEM_E_ACCESS_DENIED);
}
}
else
{
if ( !IsAdmin(hAccess))
{
CloseHandle ( hAccess );
return OpInfo.ErrorOccurred(WBEM_E_ACCESS_DENIED);
}
CloseHandle ( hAccess );
}
}
bool derivedFromSys = false;
HRESULT hr = IsDerivedFromSystem(*pClassDef, &derivedFromSys);
if (FAILED(hr)) return pSink->Return(hr);
if (derivedFromSys)
{
if (!Allowed(WBEM_FULL_WRITE_REP))
return pSink->Return(WBEM_E_ACCESS_DENIED);
}
else if (!Allowed(WBEM_PARTIAL_WRITE_REP))
{
return pSink->Return(WBEM_E_ACCESS_DENIED);
}
rmClsDef.release();
// If here, it is a normal object. First retrieve
// the object for the event subsystem, then go ahead and delete it.
// ================================================================
// Prehook.
// ========
_IWmiCoreWriteHook *pHook = 0;
hRes = m_pCoreSvc->NewPerTaskHook(&pHook);
if (FAILED(hRes)) return OpInfo.ErrorOccurred(hRes);
CReleaseMe rmHook(pHook);
HRESULT hHookResult = 0;
LPWSTR pszClassName = 0;
IWbemPath *pPath = 0;
CReleaseMeRef<IWbemPath*> rmPath(pPath);
CVectorDeleteMe<WCHAR> vdmClassName(&pszClassName);
if (pHook)
{
// Parse the object path.
hRes = m_pCoreSvc->CreatePathParser(0, &pPath);
if (FAILED(hRes)) return OpInfo.ErrorOccurred(hRes);
hRes = pPath->SetText(WBEMPATH_CREATE_ACCEPT_ALL, wszObjectPath);
if (FAILED(hRes)) return OpInfo.ErrorOccurred(hRes);
ULONG uBuf = 0;
hRes = pPath->GetClassName(&uBuf, 0);
if (FAILED(hRes)) return OpInfo.ErrorOccurred(hRes);
pszClassName = new wchar_t[uBuf+1];
if (pszClassName == 0) return OpInfo.ErrorOccurred(WBEM_E_OUT_OF_MEMORY);
hRes = pPath->GetClassName(&uBuf, pszClassName);
if (FAILED(hRes)) return OpInfo.ErrorOccurred(hRes);
// If there are hooks, try them and note whether callback is required.
// ===================================================================
hHookResult = pHook->PreDelete(WBEM_FLAG_INST_DELETE, lFlags, pCtx, pPath,m_pThisNamespace, pszClassName);
if (FAILED(hHookResult)) return OpInfo.ErrorOccurred(hHookResult);
}
// If anybody wants to see the old object, get it.
IWbemClassObject *pDoomedInstance = NULL ;
if (hHookResult == WBEM_S_POSTHOOK_WITH_OLD)
{
hRes = CRepository::GetObject(m_pSession, m_pScopeHandle, wszObjectPath,0, &pDoomedInstance);
if (FAILED(hRes)) return OpInfo.ErrorOccurred(hRes);
}
CReleaseMe _Doomed (pDoomedInstance) ;
hRes = CRepository::DeleteByPath(m_pSession, m_pScopeHandle, wszObjectPath, 0); // new
// Posthook.
if (pHook)
pHook->PostDelete(WBEM_FLAG_INST_DELETE, hRes, pCtx, pPath,
m_pThisNamespace, pszClassName, (_IWmiObject *) pDoomedInstance);
if ( FAILED (hRes) ) return OpInfo.ErrorOccurred(hRes);
return OpInfo.ErrorOccurred(WBEM_NO_ERROR);
}
//***************************************************************************
//
// CWbemNamespace::Exec_CreateInstanceEnum
//
// Actually creates the enumerator for all instances of a given class,
// optionally recursively. Interacts with instance providers. Class provider
// interaction works, but is sparsely tested.
//
// Parameters and return values are exacly the same as those for
// CreateInstanceEnum as described in help
//
//***************************************************************************
HRESULT CWbemNamespace::Exec_CreateInstanceEnum(
LPWSTR wszClass,
long lFlags,
IWbemContext* pCtx,
CBasicObjectSink* pSink
)
{
TIMETRACE(TimeTraces::CreateInstanceEnum);
COperationError OpInfo(pSink, L"CreateInstanceEnum", wszClass);
if ( !OpInfo.IsOk() ) return WBEM_E_OUT_OF_MEMORY;
// Make sure the name of the class is a name
// =========================================
if(wcschr(wszClass, L':'))
return OpInfo.ErrorOccurred(WBEM_E_INVALID_CLASS);
// Create equivalent query
// =======================
WString wsQuery;
wsQuery += L"select * from ";
wsQuery += wszClass;
if((lFlags & WBEM_MASK_DEPTH) == WBEM_FLAG_SHALLOW)
{
wsQuery += L" where __CLASS = \"";
wsQuery += wszClass;
wsQuery += L"\"";
}
CErrorChangingSink* pErrSink = new CErrorChangingSink(OpInfo.GetSink(),WBEM_E_INVALID_QUERY, WBEM_E_INVALID_CLASS);
if(pErrSink == NULL) return OpInfo.ErrorOccurred(WBEM_E_OUT_OF_MEMORY);
CReleaseMe rmErrorChange(pErrSink);
// Execute it
CQueryEngine::ExecQuery(this,L"WQL",(LPWSTR)wsQuery,lFlags,pCtx,pErrSink);
return WBEM_S_NO_ERROR;
}
//***************************************************************************
//
//***************************************************************************
/*
void CWbemNamespace::SetUserName(LPWSTR wName)
{
try
{
delete m_wszUserName;
m_wszUserName = (wName) ? Macro_CloneLPWSTR(wName):NULL;
}
catch(...)
{
ExceptionCounter c;
m_wszUserName = 0;
}
}
*/
//***************************************************************************
//
//***************************************************************************
HRESULT CWbemNamespace::GetObjectByFullPath(
READONLY LPWSTR wszObjectPath,
IWbemPath * pOutput,
long lFlags,
IWbemContext* pCtx,
CBasicObjectSink* pSink
)
{
// Get the namespace part of the path
DWORD dwSizeNamespace = 0;
HRESULT hres = pOutput->GetText(WBEMPATH_GET_NAMESPACE_ONLY, &dwSizeNamespace, NULL);
if(FAILED(hres))
return hres;
LPWSTR wszNewNamespace = new WCHAR[dwSizeNamespace];
if(wszNewNamespace == NULL)
return WBEM_E_OUT_OF_MEMORY;
CDeleteMe<WCHAR> dm1(wszNewNamespace);
hres = pOutput->GetText(WBEMPATH_GET_NAMESPACE_ONLY, &dwSizeNamespace, wszNewNamespace);
if(FAILED(hres))
return hres;
// Get the relative part of the path
DWORD dwSizeRelative = 0;
hres = pOutput->GetText(WBEMPATH_GET_RELATIVE_ONLY, &dwSizeRelative, NULL);
if(FAILED(hres))
return hres;
LPWSTR wszRelativePath = new WCHAR[dwSizeRelative];
if(wszRelativePath == NULL)
return WBEM_E_OUT_OF_MEMORY;
CDeleteMe<WCHAR> dm2(wszRelativePath);
hres = pOutput->GetText(WBEMPATH_GET_RELATIVE_ONLY, &dwSizeRelative, wszRelativePath);
if(FAILED(hres))
return hres;
if (pOutput->IsLocal(ConfigMgr::GetMachineName()))
{
// In win2k, we allowed \\.\root\default:whatever, but not root\default:whatever
// So, the following additional test was added
ULONGLONG uFlags;
hres = pOutput->GetInfo(0, &uFlags);
if(SUCCEEDED(hres))
{
if((uFlags & WBEMPATH_INFO_PATH_HAD_SERVER) == 0)
return pSink->Return(WBEM_E_INVALID_OBJECT_PATH);
}
bool bAlreadyAuthenticated = (m_dwSecurityFlags & SecFlagWin9XLocal) != 0;
CWbemNamespace* pNewLocal = CWbemNamespace::CreateInstance();
if(pNewLocal == NULL)
return WBEM_E_OUT_OF_MEMORY;
hres = pNewLocal->Initialize(wszNewNamespace, m_wszUserName,
(bAlreadyAuthenticated) ? m_dwSecurityFlags : 0,
(bAlreadyAuthenticated) ? m_dwPermission : 0,
m_bForClient, false,
m_pszClientMachineName,
m_dwClientProcessID,
FALSE,NULL);
if (FAILED(hres))
{
pNewLocal->Release();
return hres;
}
else if (pNewLocal->GetStatus())
{
hres = pNewLocal->GetStatus();
pNewLocal->Release();
return hres;
}
// check for security if this isnt the local 9x case
if(!bAlreadyAuthenticated)
{
DWORD dwAccess = pNewLocal->GetUserAccess();
if((dwAccess & WBEM_ENABLE) == 0)
{
delete pNewLocal;
return WBEM_E_ACCESS_DENIED;
}
else
pNewLocal->SetPermissions(dwAccess);
}
if(pNewLocal->GetStatus())
{
hres = pNewLocal->GetStatus();
delete pNewLocal;
return pSink->Return(hres);
}
#if 0
pNewLocal->AddRef();
#endif
pNewLocal->SetLocale(GetLocale());
hres = pNewLocal->Exec_GetObject(wszRelativePath,
lFlags, pCtx, pSink);
pNewLocal->Release();
return hres;
}
else
{
// Disable remote retrieval for V1
// ===============================
return pSink->Return(WBEM_E_NOT_SUPPORTED);
}
}
//***************************************************************************
//
// CWbemNamespace::Exec_GetObjectByPath
//
// Actually retrieves an object (a class or an instance) from the database.
// Interacts properly with class and instance providers and uses property
// providers for post-processing (See GetOrPutDynProps).
//
// Parameters and return values are exacly the same as those for GetObject
// as described in help
//
//***************************************************************************
HRESULT CWbemNamespace::Exec_GetObjectByPath(
READONLY LPWSTR wszObjectPath,
long lFlags,
IWbemContext* pCtx,
NEWOBJECT IWbemClassObject** ppObj,
NEWOBJECT IWbemClassObject** ppErrorObj
)
{
TIMETRACE(TimeTraces::GetObjectByPath);
HRESULT hres = WBEM_S_NO_ERROR;
CSynchronousSink* pSyncSink = CSynchronousSink::Create();
if(pSyncSink == NULL)
return WBEM_E_OUT_OF_MEMORY;
pSyncSink->AddRef();
IWbemClassObject* pErrorObj = NULL;
IWbemClassObject* pObj = NULL;
hres = Exec_GetObject(wszObjectPath, lFlags, pCtx, pSyncSink);
if (SUCCEEDED(hres))
{
pSyncSink->Block();
pSyncSink->GetStatus(&hres, NULL, &pErrorObj);
if(SUCCEEDED(hres))
{
if(pSyncSink->GetObjects().GetSize() < 1)
{
pSyncSink->Release();
ERRORTRACE((LOG_WBEMCORE, "Sync sink returned success with no objects!\n"));
return WBEM_E_CRITICAL_ERROR;
}
pObj = pSyncSink->GetObjects()[0];
pObj->AddRef();
}
}
pSyncSink->Release();
if(ppObj) *ppObj = pObj;
else if(pObj) pObj->Release();
if(ppErrorObj) *ppErrorObj = pErrorObj;
else if(pErrorObj) pErrorObj->Release();
return hres;
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWbemNamespace::Exec_GetObject(
READONLY LPWSTR wszObjectPath,
long lFlags,
IWbemContext* pCtx,
CBasicObjectSink* pSink)
{
TIMETRACE(TimeTraces::GetObject);
// Create a sink that will merge the localized qualifiers
// over the top of the default qualifiers (if specified)
// ======================================================
CLocaleMergingSink *pLocaleSink = NULL;
HRESULT hres = WBEM_S_NO_ERROR;
if (wszObjectPath && wszObjectPath[0] && wszObjectPath[0] != L'_') // SEC:REVIEWED 2002-03-22 : OK; prior testing ensures that this is valid
{
if ((lFlags & WBEM_FLAG_USE_AMENDED_QUALIFIERS))
{
pLocaleSink = new CLocaleMergingSink(pSink, m_wsLocale, m_pThisNamespace);
if(pLocaleSink == NULL)
return pSink->Return(WBEM_E_OUT_OF_MEMORY);
else
{
pLocaleSink->AddRef();
pSink = pLocaleSink;
}
}
}
CReleaseMe rm(pLocaleSink);
COperationError OpInfo(pSink, L"GetObject", wszObjectPath?wszObjectPath:L"");
if (!OpInfo.IsOk()) return pSink->Return(WBEM_E_OUT_OF_MEMORY);
// Check if the path is NULL --- that's valid
// ==========================================
if (wszObjectPath == NULL || wszObjectPath[0] == 0) // SEC:REVIEWED 2002-03-22 : OK; null terminator provably exists
{
//
// BUGBUG consider using CoCreateInstance instead of new CWbemClass
//
CWbemClass * pNewObj = new CWbemClass;
if(NULL == pNewObj) return OpInfo.ErrorOccurred(WBEM_E_OUT_OF_MEMORY);
CReleaseMe rm_((IWbemClassObject*)pNewObj);
hres = pNewObj->InitEmpty(0);
if (FAILED(hres)) return OpInfo.ErrorOccurred(hres);
IWbemClassObject* pObj = pNewObj;
pSink->Indicate(1, &pObj);
return OpInfo.ErrorOccurred(WBEM_NO_ERROR);
}
// here we are sure the path is not null
if (wcslen_max(wszObjectPath,g_PathLimit) > g_PathLimit)
return OpInfo.ErrorOccurred(WBEM_E_QUOTA_VIOLATION);
// Parse the object path to get the class involved.
// ================================================
IWbemPath *pPath = ConfigMgr::GetNewPath();
if (pPath == 0)
{
return OpInfo.ErrorOccurred(WBEM_E_OUT_OF_MEMORY);
}
CReleaseMe _1(pPath);
hres = pPath->SetText(WBEMPATH_CREATE_ACCEPT_ALL, wszObjectPath);
if (FAILED(hres))
{
return OpInfo.ErrorOccurred(WBEM_E_INVALID_OBJECT_PATH);
}
ULONGLONG uResponse;
hres = pPath->GetInfo(0, &uResponse);
if (FAILED(hres) || (
(uResponse & WBEMPATH_INFO_IS_INST_REF) == 0 &&
(uResponse & WBEMPATH_INFO_IS_CLASS_REF) == 0))
{
return OpInfo.ErrorOccurred(WBEM_E_INVALID_OBJECT_PATH);
}
if (!pPath->IsRelative(ConfigMgr::GetMachineName(), m_pThisNamespace))
{
// This path points to another namespace. Delegate to it instead
// =============================================================
hres = GetObjectByFullPath(wszObjectPath, pPath,
lFlags, pCtx, OpInfo.GetSink());
return OpInfo.ErrorOccurred(hres);
}
BOOL bInstance = (uResponse & WBEMPATH_INFO_IS_INST_REF);
// The repository code can't handle paths like root\default:classname
// So if there is a colon, pass a pointer to one past it
WCHAR * pRelativePath = wszObjectPath;
for(WCHAR * pTest = wszObjectPath;*pTest;pTest++)
{
if(*pTest == L':')
{
// In win2k, we allowed \\.\root\default:whatever, but not root\default:whatever
// So, the following additional test was added
if((uResponse & WBEMPATH_INFO_PATH_HAD_SERVER) == 0)
return OpInfo.ErrorOccurred(WBEM_E_INVALID_OBJECT_PATH);
pRelativePath = pTest+1;
break;
}
else if (*pTest==L'=')
break; //got to key part...
}
if (bInstance)
{
CFinalizingSink* pFinalSink = new CFinalizingSink(this, OpInfo.GetSink());
if(pFinalSink == NULL) return OpInfo.ErrorOccurred(WBEM_E_OUT_OF_MEMORY);
pFinalSink->AddRef();
CReleaseMe rmFinal(pFinalSink);
hres = Exec_GetInstance(pRelativePath, pPath, lFlags, pCtx, pFinalSink);
if (FAILED(hres)) return OpInfo.ErrorOccurred(hres);
}
else
{
hres = Exec_GetClass(pRelativePath, lFlags, pCtx, OpInfo.GetSink());
if (FAILED(hres)) return OpInfo.ErrorOccurred(hres);
}
return hres;
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWbemNamespace::Exec_GetInstance(LPCWSTR wszObjectPath,
IWbemPath* pParsedPath, long lFlags, IWbemContext* pCtx,
CBasicObjectSink* pSink)
{
if (pParsedPath->IsSameClassName(L"__NTLMUser") ||
pParsedPath->IsSameClassName(L"__NTLMGroup"))
{
if((lFlags & WBEM_FLAG_ONLY_STATIC) == 0)
{
ParsedObjectPath* pOutput = 0; // todo, convert to use new parser
CObjectPathParser p;
int nStatus = p.Parse(wszObjectPath, &pOutput);
if (nStatus != 0)
{
p.Free(pOutput);
return WBEM_E_INVALID_OBJECT_PATH;
}
HRESULT hr = GetSecurityClassInstances(pOutput, pSink, pCtx,lFlags);
p.Free(pOutput);
return hr;
}
}
// Try static database first
// =========================
if((lFlags & WBEM_FLAG_NO_STATIC) == 0)
{
IWbemClassObject *pObj = 0;
HRESULT hRes = CRepository::GetObject(m_pSession, m_pScopeHandle, wszObjectPath, lFlags, &pObj);
if (SUCCEEDED(hRes))
{
hRes = WBEM_S_NO_ERROR;
pSink->Add(pObj);
pObj->Release();
return pSink->Return(hRes);
}
}
// Try dynamic
// ===========
return DynAux_GetInstance((LPWSTR)wszObjectPath, lFlags, pCtx, pSink);
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWbemNamespace::Exec_GetClass(
LPCWSTR pszClassName,
long lFlags,
IWbemContext* pCtx,
CBasicObjectSink* pSink
)
{
HRESULT hRes = 0;
IWbemClassObject* pErrorObj = 0;
IWbemServices *pClassProv = 0;
CSynchronousSink* pSyncSink = 0;
BSTR bstrClass = 0;
IWbemClassObject* pResultObj = 0;
if (pszClassName == 0 || pSink == 0)
return pSink->Return(WBEM_E_INVALID_PARAMETER);
if (!m_bRepositOnly && m_pProvFact)
{
hRes = m_pProvFact->GetClassProvider(
0, // lFlags
pCtx,
m_wszUserName,
m_wsLocale,
m_pThisNamespace, // IWbemPath pointer
0,
IID_IWbemServices,
(LPVOID *) &pClassProv
);
if (FAILED(hRes))
return pSink->Return(hRes);
}
CReleaseMe _1(pClassProv);
// First, try repository. If it's there, end of story.
// ====================================================
if ((lFlags & WBEM_FLAG_NO_STATIC) == 0)
{
if (m_pNsHandle)
{
hRes = CRepository::GetObject(
m_pSession,
m_pNsHandle,
pszClassName,
0,
&pResultObj
);
}
else // Something drastically wrong
{
hRes = WBEM_E_CRITICAL_ERROR;
return pSink->Return(hRes);
}
if (SUCCEEDED(hRes) && pResultObj)
{
pSink->Add(pResultObj);
pResultObj->Release();
return pSink->Return(hRes);
}
}
// If we are in repository-only mode, we don't bother
// with dynamic classes.
// ===================================================
if (m_bRepositOnly || m_pProvFact == NULL)
return pSink->Return(WBEM_E_NOT_FOUND);
// If here, try the dynamic class providers.
// =========================================
// Build up a synchronous sink to receive the class.
// =================================================
pSyncSink = CSynchronousSink::Create();
if (pSyncSink == NULL)
return pSink->Return(WBEM_E_OUT_OF_MEMORY);
pSyncSink->AddRef();
CReleaseMe _2(pSyncSink);
// Try to get it.
// ==============
bstrClass = SysAllocString(pszClassName);
if (bstrClass == 0) return pSink->Return(WBEM_E_OUT_OF_MEMORY);
CSysFreeMe sfm(bstrClass);
{
CDecoratingSink * pDecore = new CDecoratingSink(pSyncSink, this);
if(pDecore == NULL) return pSink->Return(WBEM_E_OUT_OF_MEMORY);
pDecore->AddRef();
CReleaseMe rmDecor(pDecore);
hRes = pClassProv->GetObjectAsync(bstrClass, lFlags & ~WBEM_FLAG_USE_AMENDED_QUALIFIERS, pCtx, pDecore);
}
if (FAILED(hRes))
return pSink->Return(hRes);
pSyncSink->Block();
pSyncSink->GetStatus(&hRes, NULL, &pErrorObj);
if (FAILED(hRes))
{
pSink->Return(hRes, pErrorObj);
if (pErrorObj)
pErrorObj->Release();
return hRes;
}
// Otherwise, somebody claimed to have supplied it. Do we really believe them? No choice.
// =======================================================================================
if(pSyncSink->GetObjects().GetSize() < 1)
{
ERRORTRACE((LOG_WBEMCORE, "Sync sink returned success with no objects!\n"));
return pSink->Return(WBEM_E_CRITICAL_ERROR);
}
pResultObj = pSyncSink->GetObjects()[0];
pSink->Add(pResultObj);
pSink->Return(WBEM_S_NO_ERROR);
return hRes;
}
//***************************************************************************
//
//***************************************************************************
// ok
HRESULT CWbemNamespace::ExecNotificationQuery(
const BSTR QueryLanguage,
const BSTR Query,
long lFlags,
IWbemContext* pCtx,
IEnumWbemClassObject** ppEnum
)
{
try
{
HRESULT hRes = CheckNs();
if (FAILED(hRes))
return hRes;
DEBUGTRACE((LOG_WBEMCORE,
"CALL CWbemNamespace::ExecNotificationQuery\n"
" BSTR QueryLanguage = %S\n"
" BSTR Query = %S\n"
" lFlags = 0x%X\n"
" IEnumWbemClassObject **pEnum = 0x%X\n",
QueryLanguage,
Query,
lFlags,
ppEnum
));
// Validate parameters
// ===================
if (ppEnum == NULL)
return WBEM_E_INVALID_PARAMETER;
*ppEnum = NULL;
if ((lFlags & WBEM_FLAG_RETURN_IMMEDIATELY) == 0)
return WBEM_E_INVALID_PARAMETER;
if ((lFlags & WBEM_FLAG_FORWARD_ONLY) == 0)
return WBEM_E_INVALID_PARAMETER;
if (lFlags
& ~WBEM_FLAG_USE_AMENDED_QUALIFIERS
& ~WBEM_RETURN_IMMEDIATELY
& ~WBEM_FLAG_FORWARD_ONLY
#ifdef _WBEM_WHISTLER_UNCUT
& ~WBEM_FLAG_MONITOR
#endif
)
return WBEM_E_INVALID_PARAMETER;
// Create Finalizer.
// =================
_IWmiFinalizer *pFnz = 0;
hRes = CreateSyncFinalizer(pCtx, &pFnz);
if (FAILED(hRes))
return hRes;
CReleaseMe _1(pFnz);
ULONG uTaskType = WMICORE_TASK_EXEC_NOTIFICATION_QUERY;
if (lFlags & WBEM_RETURN_IMMEDIATELY)
uTaskType |= WMICORE_TASK_TYPE_SEMISYNC;
else
uTaskType |= WMICORE_TASK_TYPE_SYNC;
// Do the work.
// ============
hRes = _ExecNotificationQueryAsync(uTaskType, pFnz, 0, QueryLanguage, Query,
lFlags & ~WBEM_RETURN_IMMEDIATELY & ~WBEM_FLAG_FORWARD_ONLY,
pCtx, NULL);
if (FAILED(hRes))
{
return hRes;
}
if ((lFlags & WBEM_RETURN_IMMEDIATELY) == 0)
pFnz->GetOperationResult(0, INFINITE, &hRes);
if (SUCCEEDED(hRes))
{
IEnumWbemClassObject* pEnum = NULL;
hRes = pFnz->GetResultObject(lFlags, IID_IEnumWbemClassObject, (LPVOID*)&pEnum);
if (FAILED(hRes))
return hRes;
CReleaseMe _2(pEnum);
if (SUCCEEDED(hRes))
{
*ppEnum = pEnum;
pEnum->AddRef(); // Counteract CReleaseMe
}
}
return hRes;
}
catch(...)
{
ExceptionCounter c;
return WBEM_E_CRITICAL_ERROR;
}
}
//
//
// this function can throw or return
//
//////////////////////////////////////////////////////////
HRESULT CWbemNamespace::_ExecNotificationQueryAsync(
IN ULONG uInternalFlags,
IN _IWmiFinalizer *pFnz,
IN _IWmiCoreHandle *phTask,
IN const BSTR strQueryLanguage,
IN const BSTR strQuery,
IN long lFlags,
IN IWbemContext __RPC_FAR *pCtx,
IN IWbemObjectSink __RPC_FAR *pHandler
)
{
HRESULT hRes = CheckNs();
if (FAILED(hRes))
return hRes;
if (!Allowed(WBEM_ENABLE))
return WBEM_E_ACCESS_DENIED;
DEBUGTRACE((LOG_WBEMCORE,
"CALL CWbemNamespace::_ExecNotificationQueryAsync\n"
" BSTR QueryLanguage = %S\n"
" BSTR Query = %S\n"
" lFlags = 0x%X\n"
" IWbemObjectSink* pHandler = 0x%X\n",
strQueryLanguage,
strQuery,
lFlags,
pHandler));
// Parameter validation.
// =====================
if (pFnz == 0 && pHandler == 0)
return WBEM_E_INVALID_PARAMETER;
if (strQueryLanguage == 0 || strQuery == 0 || strQueryLanguage[0] == 0)
return WBEM_E_INVALID_PARAMETER;
if (strQuery[0] == 0 )
return WBEM_E_UNPARSABLE_QUERY;
if (wcslen_max(strQuery,g_QueryLimit) > g_QueryLimit) return WBEM_E_QUOTA_VIOLATION;
if (lFlags & ~WBEM_FLAG_SEND_STATUS & ~WBEM_FLAG_USE_AMENDED_QUALIFIERS )
return WBEM_E_INVALID_PARAMETER;
m_bForClient=FALSE; // Forces a cheap fast-track
// Create Finalizer.
// =================
IWbemObjectSink *pPseudoSink = 0;
if (pFnz == 0)
{
hRes = CreateAsyncFinalizer(pCtx, pHandler, &pFnz, &pPseudoSink);
if (FAILED(hRes))
return hRes;
}
else // borrowed finalizer
{
hRes = pFnz->NewInboundSink(0, &pPseudoSink);
if (FAILED(hRes))
return hRes;
pFnz->AddRef();
}
CReleaseMe _1(pPseudoSink);
CReleaseMe _2(pFnz);
// Add the request to the queue.
// =============================
IWbemEventSubsystem_m4* pEss = ConfigMgr::GetEssSink();
CReleaseMe _3(pEss);
if (pEss == 0)
{
return WBEM_E_NOT_SUPPORTED; // ESS must be disabled
}
HANDLE hEssValidate = CreateEvent(NULL,FALSE,FALSE,NULL);
if (NULL == hEssValidate) return WBEM_E_OUT_OF_MEMORY;
CCloseMe cm(hEssValidate);
HRESULT hResEssCheck = 0;
wmilib::auto_ptr<CAsyncReq_ExecNotificationQueryAsync> pReq;
pReq.reset(new CAsyncReq_ExecNotificationQueryAsync(this, pEss, strQueryLanguage,
strQuery, lFlags, pPseudoSink, pCtx,
&hResEssCheck, hEssValidate));
if (NULL == pReq.get()) return WBEM_E_OUT_OF_MEMORY;
if ( NULL == pReq->GetContext() ) return WBEM_E_OUT_OF_MEMORY;
hRes = InitNewTask(pReq.get(), pFnz, uInternalFlags, pReq->GetContext(), pHandler);
if (FAILED(hRes)) return hRes;
_1.release();
// Enqueue the request.
hRes = ConfigMgr::EnqueueRequest(pReq.get());
if (FAILED(hRes))
{
pFnz->CancelTask (0);
return hRes;
}
pReq.release(); // queue took ownership
// In this case, we have to wait long enough for ESS to accept the task.
WaitForSingleObject(hEssValidate, INFINITE);
// If ESS failed, we should cancel the task
// ========================================
if ( FAILED (hResEssCheck) )
{
pFnz->CancelTask(0);
}
return hResEssCheck;
}
//***************************************************************************
//
//***************************************************************************
// done
HRESULT CWbemNamespace::ExecNotificationQueryAsync(
IN const BSTR strQueryLanguage,
IN const BSTR strQuery,
IN long lFlags,
IN IWbemContext __RPC_FAR *pCtx,
IN IWbemObjectSink __RPC_FAR *pHandler
)
{
try
{
return _ExecNotificationQueryAsync(WMICORE_TASK_TYPE_ASYNC | WMICORE_TASK_EXEC_NOTIFICATION_QUERY,
0, 0,
strQueryLanguage, strQuery, lFlags, pCtx, pHandler);
}
catch (...)
{
ExceptionCounter c;
return WBEM_E_CRITICAL_ERROR;
}
}
//***************************************************************************
//
//***************************************************************************
//
HRESULT CWbemNamespace::GetImplementationClass(
IWbemClassObject * pTestClass,
LPWSTR wszMethodName,
IWbemContext* pCtx,
IWbemClassObject ** ppClassObj
)
{
try
{
// If the method is disabled, or implemented in this class, we are done!
// =====================================================================
CVar Var;
CWbemClass * pClassDef = (CWbemClass *)pTestClass;
HRESULT hres = pClassDef->GetMethodQualifier(wszMethodName, L"DISABLED", &Var);
if(hres == S_OK && Var.GetBool() == VARIANT_TRUE)
return WBEM_E_METHOD_DISABLED;
hres = pClassDef->GetMethodQualifier(wszMethodName, L"IMPLEMENTED", &Var);
if(hres == S_OK && Var.GetBool() == VARIANT_TRUE)
{
// The test class is correct, return it
pTestClass->AddRef();
*ppClassObj = pTestClass;
return S_OK;
}
// Not done, get the name of the parent class.
SCODE hRes = pClassDef->GetSystemPropertyByName(L"__superclass", &Var);
if(hRes != S_OK)
return WBEM_E_CRITICAL_ERROR;
if(Var.GetType() != VT_BSTR)
return WBEM_E_METHOD_NOT_IMPLEMENTED; // no superclass --- no implementation
BSTR bstrParent = Var.GetBSTR();
if(bstrParent == NULL)
return WBEM_E_CRITICAL_ERROR; // NULL, but not VT_NULL
if(wcslen(bstrParent) < 1)
{
SysFreeString(bstrParent);
return WBEM_E_FAILED; // empty parent name????
}
IWbemClassObject * pParent = NULL;
hres = Exec_GetObjectByPath(bstrParent, 0, pCtx, &pParent, NULL);
SysFreeString(bstrParent);
if(FAILED(hres))
return WBEM_E_FAILED; // class provider failure or weird interaction
hRes = GetImplementationClass(pParent, wszMethodName, pCtx, ppClassObj);
pParent->Release();
return hRes;
}
catch(CX_Exception &)
{
return WBEM_E_FAILED;
}
}
//***************************************************************************
//
// CWbemNamespace::Exec_ExecMethod
//
// Executes a method. If the method is not tagged by the [bypass_getobject]
// qualifier, the method is passed directly to the method provider. Otherwise,
// a GetObject call is done first to ensure the instance is valid.
//
//***************************************************************************
//
HRESULT CWbemNamespace::Exec_ExecMethod(
LPWSTR wszObjectPath,
LPWSTR wszMethodName,
long lFlags,
IWbemClassObject *pInParams,
IWbemContext *pCtx,
CBasicObjectSink* pSink
)
{
TIMETRACE(TimeTraces::ExecMethod);
// Lotsa useful variables.
// =======================
HRESULT hRes;
IWbemClassObject* pClassDef = NULL;
IWbemClassObject* pImplementationClass = NULL;
IWbemPath *pPath = 0;
IWbemQualifierSet *pQSet = 0;
IWbemClassObject* pErrorObj = NULL;
BOOL bPathIsToClassObject = FALSE;
LPWSTR pszClassName = 0;
ULONGLONG uInf = 0;
// Set up a sink error object and check it.
COperationError OpInfo(pSink, L"ExecMethod", wszObjectPath);
if ( !OpInfo.IsOk() ) return WBEM_E_OUT_OF_MEMORY;
// Parse the path to the object.
// =============================
// Backwards compatibility - parsing a NULL path returns WBEM_E_INVALID_OBJECT_PATH
if ( NULL == wszObjectPath || NULL == *wszObjectPath )
{
return OpInfo.ErrorOccurred( WBEM_E_INVALID_METHOD );
}
hRes = m_pCoreSvc->CreatePathParser(0, &pPath);
if (FAILED(hRes))
return OpInfo.ErrorOccurred(hRes);
CReleaseMe _1(pPath);
hRes = pPath->SetText(WBEMPATH_CREATE_ACCEPT_ALL, wszObjectPath);
if (FAILED(hRes))
return OpInfo.ErrorOccurred(hRes);
ULONG uBuf = 0;
hRes = pPath->GetClassName(&uBuf, 0); // Discover the buffer size
if (FAILED(hRes))
return OpInfo.ErrorOccurred(hRes);
pszClassName = new wchar_t[uBuf+1]; // Allocate a buffer for the class name
if (pszClassName == 0)
return OpInfo.ErrorOccurred(WBEM_E_OUT_OF_MEMORY);
wmilib::auto_buffer <wchar_t> _2(pszClassName); // Auto-delete buffer
hRes = pPath->GetClassName(&uBuf, pszClassName); // Get class name
if (FAILED(hRes))
return OpInfo.ErrorOccurred(hRes);
// Find out if a path to an instance or a class.
// ==============================================
hRes = pPath->GetInfo(0, &uInf);
if (FAILED(hRes))
return OpInfo.ErrorOccurred(hRes);
if (uInf & WBEMPATH_INFO_IS_INST_REF)
bPathIsToClassObject = FALSE;
else
bPathIsToClassObject = TRUE;
// Get the class definition. We'll need it whether or not we validate the
// instance or not.
// =======================================================================
hRes = Exec_GetObjectByPath(pszClassName,
(lFlags & WBEM_FLAG_USE_AMENDED_QUALIFIERS), pCtx,
&pClassDef, &pErrorObj);
if (FAILED(hRes))
{
OpInfo.ErrorOccurred(hRes, pErrorObj);
if (pErrorObj)
pErrorObj->Release();
return hRes;
}
CReleaseMe _3(pClassDef);
// Now see if the method exists and if the class definition
// has the [bypass_getobject] qualifier on that method.
// ========================================================
hRes = pClassDef->GetMethodQualifierSet(wszMethodName, &pQSet);
if (FAILED(hRes))
{
// Means the method doesn't even exist
if ( WBEM_E_NOT_FOUND == hRes )
{
hRes = WBEM_E_INVALID_METHOD;
}
return OpInfo.ErrorOccurred(hRes);
}
CReleaseMe _4(pQSet);
hRes = pQSet->Get(L"bypass_getobject", 0, 0, 0);
if (hRes == WBEM_E_NOT_FOUND)
{
// If here, we are going to get the object pointed to by the path first to ensure it is
// valid. Note that the object may be either an instance or class object
//
// First, merge in the __GET_EXT_KEYS_ONLY during the GetObject calls to allow
// the provider to quickly verify the existence of the object. We don't
// actually care about the property values other than the keys. We use
// a copy of the context object, as we want to merge in KEYS_ONLY behavior
// for the next call only.
// ============================================================================
IWbemClassObject *pVerifiedObj = 0;
IWbemContext *pCopy = 0;
if (pCtx)
pCtx->Clone(&pCopy);
hRes = MergeGetKeysCtx(pCopy);
if (FAILED(hRes))
return OpInfo.ErrorOccurred(hRes);
// If here, we are verifying the object exists before passing the
// control to the method handler.
// ==============================================================
hRes = Exec_GetObjectByPath(wszObjectPath, lFlags, pCopy,
&pVerifiedObj, &pErrorObj);
if (pCopy)
pCopy->Release();
if (FAILED(hRes))
{
OpInfo.ErrorOccurred(hRes, pErrorObj);
if (pErrorObj)
pErrorObj->Release();
return hRes;
}
// If here, the class or instance exists!!
// =======================================
pVerifiedObj->Release();
}
else if (FAILED(hRes))
{
return OpInfo.ErrorOccurred(hRes);
}
// If this is the special internal security object, handle it internally
// ======================================================================
CVar Value;
hRes = ((CWbemClass *) pClassDef)->GetSystemPropertyByName(L"__CLASS", &Value);
if (hRes == S_OK && Value.GetType() == VT_BSTR && !Value.IsDataNull())
if (!wbem_wcsicmp(Value.GetLPWSTR(), L"__SystemSecurity"))
return SecurityMethod(wszMethodName, lFlags, pInParams, pCtx, pSink);
// Make sure we have security.
// ===========================
if (!Allowed(WBEM_METHOD_EXECUTE))
return OpInfo.ErrorOccurred(WBEM_E_ACCESS_DENIED);
// Now, we locate the exact implementation of the method. After all, the
// subclass may have been very lazy and relied on its parent implementation,
// the way many kids rely on their parents for gas money.
// =========================================================================
hRes = GetImplementationClass(pClassDef, wszMethodName, pCtx, &pImplementationClass);
if (FAILED(hRes))
return OpInfo.ErrorOccurred(hRes);
// The "pImplementatinClass" now points to the class object where the methods is implemented
// =========================================================================================
CReleaseMe rm2(pImplementationClass);
CWbemClass * pImplementationDef = (CWbemClass*)pImplementationClass;
// Make sure that class paths are only used with static methods.
// =============================================================
CVar Var;
if (bPathIsToClassObject)
{
hRes = pImplementationDef->GetMethodQualifier(wszMethodName, L"STATIC", &Var);
if (hRes != S_OK || Var.GetBool() != VARIANT_TRUE)
{
return OpInfo.ErrorOccurred(WBEM_E_INVALID_METHOD_PARAMETERS);
}
}
// Get the provider name.
// ======================
CVar vProv;
hRes = pImplementationDef->GetQualifier(L"Provider", &vProv);
if (FAILED(hRes) || vProv.GetType() != VT_BSTR)
return OpInfo.ErrorOccurred(WBEM_E_INVALID_PROVIDER_REGISTRATION);
// Adjust the path to reference the class of implementation
// ========================================================
CVar vImpClassName;
hRes = pImplementationDef->GetClassName(&vImpClassName);
if (FAILED(hRes) || vImpClassName.GetType() != VT_BSTR)
return OpInfo.ErrorOccurred(WBEM_E_CRITICAL_ERROR);
BSTR strNewPath = CQueryEngine::AdjustPathToClass(wszObjectPath,
vImpClassName.GetLPWSTR());
if (strNewPath == NULL)
return OpInfo.ErrorOccurred(WBEM_E_CRITICAL_ERROR);
CSysFreeMe sfm1(strNewPath);
// Load the provider and execute it.
// ==================================
CMethodSink * pMethSink = new CMethodSink(OpInfo.GetSink());
if(pMethSink == NULL)
return OpInfo.ErrorOccurred(WBEM_E_OUT_OF_MEMORY);
pMethSink->AddRef();
CReleaseMe _5(pMethSink);
// Find provider.
// ==============
IWbemServices *pProv = 0;
if(m_pProvFact == NULL)
hRes = WBEM_E_CRITICAL_ERROR;
else
{
WmiInternalContext t_InternalContext ;
ZeroMemory ( & t_InternalContext , sizeof ( t_InternalContext ) ) ; // SEC:REVIEWED 2002-03-22 : OK
hRes = m_pProvFact->GetProvider(
t_InternalContext ,
0, // lFlags
pCtx,
0,
m_wszUserName,
m_wsLocale,
0, // IWbemPath pointer
vProv, // Provider
IID_IWbemServices,
(LPVOID *) &pProv
);
}
if (FAILED(hRes))
{
return pSink->Return(hRes);
}
CReleaseMe _(pProv);
hRes = pProv->ExecMethodAsync(
strNewPath,
wszMethodName,
lFlags& ~WBEM_FLAG_USE_AMENDED_QUALIFIERS,
pCtx,
pInParams,
pMethSink
);
return hRes;
}
//***************************************************************************
//
// CWbemNamespace::GetOrPutDynProps
//
// Processes an instance to see if any properties have been marked
// as 'dynamic'.
//
// Short-circuit logic is in effect. The instance as a whole must be
// marked with the following Qualifier to signal that the instance has
// dynamic properties which need evaluation:
//
// "DYNPROPS" (VT_BOOL) = VARIANT_TRUE
//
// Optionally, the instance may contain:
// "INSTANCECONTEXT" VT_BSTR = <provider specific string>
//
// In addition, each dynamic property is marked
//
// "DYNAMIC" VT_BOOL VARIANT_TRUE
// "LOCATORCLSID" VT_BSTR CLSID of the provider
// "PROPERTYCONTEXT" VT_BSTR <provider specific string>
//
// "INSTANCECONTEXT" and "PROPERTYCONTEXT" are not checked by this code,
// since they are optional for each provider.
//
// PARAMETERS:
//
// IWbemClassObject* pObj The object to fill in dynamic properties
// in.
// Operation op Can be GET or PUT depending on what is
// needed.
// bool bIsDynamic True if a dynamically provided class. Note that it
// would be very strange to have a dynamic class with
// dynamic properties.
// RETURN VALUES:
// <WBEM_NO_ERROR> No provider was involved or if a provider was
// involved, properties were all evaluated.
//
// <WBEM_E_INVALID_OBJECT>
// Object was marked as dynamic, but other Qualifiers were missing.
//
// <WBEM_E_PROVIDER_NOT_FOUND>
// One or more of the specified providers could not be found.
//
// <WBEM_E_PROVIDER_FAILURE>
// One or more providers were not able to provide the properties.
//
// <WBEM_E_CRITICAL_ERROR>
//
//***************************************************************************
HRESULT CWbemNamespace::GetOrPutDynProps(
IWbemClassObject *pObj,
Operation op,
BOOL bIsDynamic
)
{
HRESULT hRes;
IWbemContext *pCtx = 0;
CVar vDynTest;
_IWmiDynamicPropertyResolver *pResolver = 0;
IWbemQualifierSet *pQSet = 0;
IWbemClassObject *pClassDef = 0;
CVARIANT v;
// Examine the instance to see if there are any dynamic properties.
// ================================================================
hRes = pObj->GetQualifierSet(&pQSet);
if (FAILED(hRes))
return WBEM_NO_ERROR;
CReleaseMe _1(pQSet);
hRes = pQSet->Get(L"DYNPROPS", 0, &v, 0);
if (FAILED(hRes))
return WBEM_S_NO_ERROR;
if (v.GetBool() == FALSE)
return WBEM_S_NO_ERROR;
v.Clear();
hRes = pObj->Get(L"__CLASS", 0, &v, 0, 0);
if (FAILED(hRes))
return hRes;
// Get the class definition for the object.
// Must be static.
// ========================================
hRes = CRepository::GetObject(
m_pSession,
m_pNsHandle,
v.GetStr(),
0,
&pClassDef
);
CReleaseMe _2(pClassDef);
if (FAILED(hRes))
return hRes;
// Access provider subsystem to do the dirty work.
// ================================================
if (m_pProvFact == NULL)
hRes = WBEM_E_CRITICAL_ERROR;
else
{
pCtx = ConfigMgr::GetNewContext();
if ( pCtx == NULL )
return WBEM_E_OUT_OF_MEMORY;
hRes = m_pProvFact->GetDynamicPropertyResolver (
0, // lFlags
pCtx, // context
m_wszUserName,
m_wsLocale,
IID__IWmiDynamicPropertyResolver,
(LPVOID *)&pResolver);
}
CReleaseMe _1_pCtx (pCtx) ;
if (FAILED(hRes))
return hRes;
CReleaseMe _3(pResolver);
// Determine if a put or a get.
// ============================
if (op == GET)
{
hRes = pResolver->Read(pCtx, pClassDef, &pObj);
}
else if (op == PUT)
{
hRes = pResolver->Write(pCtx, pClassDef, pObj);
}
else
return WBEM_E_INVALID_PARAMETER;
return hRes;
}
//***************************************************************************
//
// AddKey
//
// Adds a keyname/value pair to a normalized path
//
// throw CX_MemoryException
//
//***************************************************************************
HRESULT AddKey(WString & wNormalString, WCHAR * pwsKeyName, VARIANT *pvKeyValue,
int & iNumKey, CWbemInstance* pClassDef)
{
if(iNumKey++ > 0)
wNormalString += L","; // prepend comma for all but the first key
wNormalString += pwsKeyName;
wNormalString += "=";
if(pvKeyValue->vt == VT_BSTR)
{
wNormalString += L"\"";
// if there are any quotes, they must be prepended with a back slash;
// Also, any back slashes should be doubled up.
int iLen = 1; // one for the terminator;
WCHAR * pTest;
for(pTest = pvKeyValue->bstrVal;*pTest; pTest++, iLen++)
if(*pTest == L'\"' || *pTest == L'\\')
iLen++;
WCHAR * pString = new WCHAR[iLen];
if(pString == NULL)
throw CX_MemoryException();
wmilib::auto_buffer<WCHAR> rm_(pString);
WCHAR * pTo = pString;
for(pTest = pvKeyValue->bstrVal;*pTest; pTest++, pTo++)
{
if(*pTest == L'\"' || *pTest == L'\\')
{
*pTo = L'\\';
pTo++;
}
*pTo = *pTest;
}
*pTo = 0;
wNormalString += pString;
wNormalString += L"\"";
return S_OK;
}
if(pvKeyValue->vt != VT_EMPTY && pvKeyValue->vt != VT_NULL)
{
// special case for large unsigned numbers
if(pvKeyValue->vt == VT_I4 && pvKeyValue->lVal < 0)
{
CIMTYPE ct;
HRESULT hRes = pClassDef->Get(pwsKeyName, 0, NULL, &ct, NULL);
if(hRes == S_OK && ct == CIM_UINT32)
{
WCHAR wBuff[32];
StringCchPrintfW(wBuff, 32, L"%u",pvKeyValue->lVal);
wNormalString += wBuff;
return S_OK;
}
}
_variant_t var;
HRESULT hRes = VariantChangeType(&var, pvKeyValue, 0, VT_BSTR);
if(hRes == S_OK)
{
wNormalString += var.bstrVal;
}
return hRes;
}
return WBEM_E_INVALID_OBJECT_PATH;
}
//***************************************************************************
//
// NormalizeObjectPath
//
// Creates a normalized object path for passing to providers.
//***************************************************************************
HRESULT NormalizeObjectPath(ParsedObjectPath*pOutput, WString & wNormalString,
CWbemInstance* pClassDef)
{
try
{
HRESULT hRes;
// For singleton, so long as the class is singleton
if(pOutput->m_bSingletonObj)
{
CVar Singleton;
hRes = pClassDef->GetQualifier(L"SINGLETON", &Singleton);
if (hRes == 0 && Singleton.GetBool() != 0)
{
wNormalString = pOutput->m_pClass;
wNormalString += "=@";
return S_OK;
}
else
return WBEM_E_INVALID_OBJECT_PATH;
}
int iKeyNum = 0;
int iNumMatch = 0; // number of keys in the path which were found in the class def
// Start off by writting the class name followe by a dot
wNormalString = pOutput->m_pClass;
wNormalString += L".";
CWStringArray ClassKeyNames;
if(!pClassDef->GetKeyProps(ClassKeyNames))
return WBEM_E_INVALID_CLASS;
// For each key in the class definition
for(int iClassKey = 0; iClassKey < ClassKeyNames.Size(); iClassKey++)
{
// look for the class key in the path
bool bClassKeyIsInPath = false;
int iPathKey;
for(iPathKey = 0; iPathKey < pOutput->m_dwNumKeys; iPathKey++)
{
KeyRef * key = pOutput->m_paKeys[iPathKey];
if(key->m_pName == 0 && ClassKeyNames.Size() == 1 && pOutput->m_dwNumKeys==1)
{
bClassKeyIsInPath = true;
break;
}
else if(key->m_pName && !wbem_wcsicmp(key->m_pName, ClassKeyNames[iClassKey]))
{
bClassKeyIsInPath = true;
break;
}
}
if(bClassKeyIsInPath)
{
iNumMatch++;
// todo, check type
KeyRef * key = pOutput->m_paKeys[iPathKey];
hRes = AddKey(wNormalString, ClassKeyNames[iClassKey],
&key->m_vValue, iKeyNum, pClassDef);
if(FAILED(hRes))
return hRes;
}
else
{
// If the key has a default value, then use it
_variant_t var;
hRes = pClassDef->Get(ClassKeyNames[iClassKey], 0, &var, NULL, NULL);
if(FAILED(hRes) || var.vt == VT_EMPTY || var.vt == VT_NULL)
return WBEM_E_INVALID_OBJECT_PATH;
hRes = AddKey(wNormalString, ClassKeyNames[iClassKey], &var, iKeyNum,pClassDef);
if(FAILED(hRes))
return hRes;
}
}
if(iNumMatch == pOutput->m_dwNumKeys)
return S_OK;
else
return WBEM_E_INVALID_OBJECT_PATH;
}
catch (CX_MemoryException &)
{
return WBEM_E_OUT_OF_MEMORY;
}
}
//***************************************************************************
//
// CWbemNamespace::DynAux_GetInstance
//
// Retrieves an instance identified by its path from the dynamic provider
// registered for that class.
//
// PARAMETERS:
//
// IN DWORD dwNamespace Namespace handle to the current
// namespace (see objdb.h)
// IN LPWSTR pObjectPath Object path to the instance.
// IN long lFlags Flags. Propagated to provider.
// OUT IWbemClassObject** pObj Destination for the class definition.
// The caller must release this object
// if the call is successful.
// OUT IWbemClassObject** ppErrorObj Destination for the error object. May
// be NULL. Otherwise, the returned
// pointer must be released if not NULL.
// RETURN VALUES:
//
// WBEM_S_NO_ERROR Success.
// WBEM_E_NOT_FOUND No such instance, says provider, or the
// class is not dynamic.
// WBEM_E_INVALID_PARAMETER One or more parameters are invalid.
// WBEM_E_INVALID_CLASS The class specified in the path does not
// exist.
// WBEM_E_FAILED Unexpected error occured.
// WBEM_E_PROVIDER_NOT_FOUND Provider for this class could not be
// located --- not registered with us or COM.
// WBEM_E_PROVIDER_FAILURE Provider reported an error while looking
// for this object.
// WBEM_E_PROVIDER_NOT_CAPABLE Provider for this class is not capable of
// getting objects by path.
//
//***************************************************************************
HRESULT CWbemNamespace::DynAux_GetInstance(
IN LPWSTR wszObjectPath,
IN long lFlags,
IN IWbemContext* pCtx,
IN CBasicObjectSink* pSink
)
{
// Parse the object path to get the class involved.
// ================================================
ParsedObjectPath* pOutput = 0;
CObjectPathParser p;
int nStatus = p.Parse(wszObjectPath, &pOutput);
OnDeleteObj<ParsedObjectPath*,CObjectPathParser,
void (CObjectPathParser:: *)(ParsedObjectPath *),
&CObjectPathParser::Free> FreeMe(&p,pOutput);
if(CObjectPathParser::NoError != nStatus || !pOutput->IsInstance())
return pSink->Return(WBEM_E_INVALID_OBJECT_PATH);
HRESULT hres = WBEM_E_FAILED;
IWbemClassObject* pErrorObj = NULL;
CReleaseMeRef<IWbemClassObject*> rmErrObj(pErrorObj);
CSetStatusOnMe SetMe(pSink,hres,pErrorObj);
// See if this class is actually provided dynamically
BSTR strClass = SysAllocString(pOutput->m_pClass);
if (NULL == strClass)
{
return hres = WBEM_E_OUT_OF_MEMORY;
}
CSysFreeMe sfm(strClass);
CWbemInstance *pClassDef = 0;
IWbemClassObject* pClassObj = NULL;
hres = Exec_GetObjectByPath(strClass,
lFlags & WBEM_FLAG_USE_AMENDED_QUALIFIERS,
pCtx,&pClassObj, NULL);
if(FAILED(hres))
{
hres = (hres == WBEM_E_NOT_FOUND) ? WBEM_E_INVALID_CLASS : WBEM_E_FAILED;
return hres;
}
CReleaseMe rm(pClassObj);
pClassDef = (CWbemInstance*)pClassObj;
WString wNormalPath;
hres = NormalizeObjectPath(pOutput, wNormalPath, pClassDef);
if(FAILED(hres)) return hres;
if(!pClassDef->IsKeyed())
return hres = WBEM_E_INVALID_CLASS;
// Make sure that this class is not static ---
// i.e. either dynamic or abstract
// ===========================================
CVar vDynamic;
hres = pClassDef->GetQualifier(L"Dynamic", &vDynamic);
if(FAILED(hres) || vDynamic.GetType() != VT_BOOL || !vDynamic.GetBool())
{
// Not dynamic. Check if it is abstract
// ====================================
CVar vAbstract;
hres = pClassDef->GetQualifier(L"Abstract", &vAbstract);
if(FAILED(hres) || vAbstract.GetType() != VT_BOOL || !vAbstract.GetBool())
return hres = WBEM_E_NOT_FOUND;
}
// Build the class hierarchy
// =========================
wmilib::auto_ptr<CDynasty> pDynasty;
hres = DynAux_BuildClassHierarchy(strClass, lFlags, pCtx, pDynasty,&pErrorObj);
if(FAILED(hres)) return hres;
rmErrObj.release(); // set it to null anyway
// If direct read is requested, only ask the provider in question.
// ===============================================================
if (lFlags & WBEM_FLAG_DIRECT_READ)
{
DynAux_GetSingleInstance((CWbemClass*) pClassObj,lFlags, wszObjectPath, pCtx, pSink);
}
else
{
// Create merging sink
hres = WBEM_E_OUT_OF_MEMORY; // pre-set the failure
CSingleMergingSink* pMergeSink = new CSingleMergingSink(pSink, strClass); // throw
if(pMergeSink == NULL) return hres;
pMergeSink->AddRef();
CReleaseMe rm(pMergeSink);
// Ask all providers
DynAux_AskRecursively(pDynasty.get(), lFlags, wNormalPath, pCtx,pMergeSink);
}
SetMe.dismiss();
return WBEM_S_NO_ERROR;
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWbemNamespace::DynAux_AskRecursively(CDynasty* pDynasty,
long lFlags,
LPWSTR wszObjectPath,
IWbemContext* pCtx,
CBasicObjectSink* pSink)
{
// Convert the path to the new class
// =================================
BSTR strNewPath = CQueryEngine::AdjustPathToClass(wszObjectPath, pDynasty->m_wszClassName);
if(strNewPath == NULL) return pSink->Return(WBEM_E_INVALID_OBJECT_PATH);
CSysFreeMe sfm(strNewPath);
// Get this provider's object
// ==========================
DynAux_GetSingleInstance((CWbemClass*)pDynasty->m_pClassObj,lFlags, strNewPath, pCtx, pSink);
// Get the children's objects
// ==========================
for(int i = 0; i < pDynasty->m_Children.Size(); i++)
{
CDynasty* pChildDyn = (CDynasty*)pDynasty->m_Children.GetAt(i);
DynAux_AskRecursively(pChildDyn, lFlags, wszObjectPath, pCtx,pSink);
}
return WBEM_S_NO_ERROR;
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWbemNamespace::DynAux_GetSingleInstance(CWbemClass* pClassDef,
long lFlags,
LPWSTR wszObjectPath,
IWbemContext* pCtx,
CBasicObjectSink* pSink)
{
COperationError OpInfo(pSink, L"GetObject", wszObjectPath, FALSE);
// the ctor calls setstatus in bad luck case
if (!OpInfo.IsOk()) return WBEM_E_OUT_OF_MEMORY;
// Verify that the class is indeed dynamic
// =======================================
if(!pClassDef->IsDynamic())
return OpInfo.ErrorOccurred(WBEM_E_NOT_FOUND);
CVar vProvName;
HRESULT hres = pClassDef->GetQualifier(L"Provider", &vProvName);
if(FAILED(hres) || vProvName.GetType() != VT_BSTR)
return OpInfo.ErrorOccurred(WBEM_E_INVALID_PROVIDER_REGISTRATION);
OpInfo.SetProviderName(vProvName.GetLPWSTR()); //throw
// Access the provider cache.
// ==========================
IWbemServices *pProv = 0;
HRESULT hRes;
if(m_pProvFact == NULL)
hRes = WBEM_E_CRITICAL_ERROR;
else
{
WmiInternalContext t_InternalContext ;
ZeroMemory ( & t_InternalContext , sizeof ( t_InternalContext ) ) ; // SEC:REVIEWED 2002-03-22 : OK
hRes = m_pProvFact->GetProvider(
t_InternalContext ,
0, // lFlags
pCtx,
0,
m_wszUserName,
m_wsLocale,
0, // IWbemPath pointer
vProvName, // Provider
IID_IWbemServices,
(LPVOID *) &pProv
);
}
if (FAILED(hRes))
{
return pSink->Return(hRes);
}
CReleaseMe _(pProv);
CDecoratingSink * pDecore = new CDecoratingSink(OpInfo.GetSink(), this);
if(pDecore == NULL) return pSink->Return(WBEM_E_OUT_OF_MEMORY);
pDecore->AddRef();
CReleaseMe cdecor(pDecore);
hRes = pProv->GetObjectAsync(wszObjectPath, lFlags& ~WBEM_FLAG_USE_AMENDED_QUALIFIERS, pCtx, pDecore);
return hRes;
}
//***************************************************************************
//
// CWbemNamespace::DynAux_GetInstances
//
// Gets all instances from the provider specified in the class
// definition. Does no inheritance joins; this is a simple retrieval
// of all instances from the specified class.
//
// Preconditions:
// 1. The class <pClassDef> is known to be marked 'dynamic', but no
// other verification has been done on the class definition.
// 2. <pClassDef> is not NULL.
//
// Postconditions:
// 1. <aInstances> is empty on all error conditions.
//
// PARAMETERS:
//
// READONLY CWbemObject *pClassDef The definition of the class to retrieve
// instances of.
// long lFlags The flags (deep/shallow)
// CFlexArray &aInstances Destination for the instances.
// IWbemClassObject** ppErrorObj Destination for the error object. If
// not NULL, an error object may be placed
// here. It is the caller's responsibility
// to release it if not NULL.
// RETURN VALUES:
//
// WBEM_NO_ERROR No errors. This includes a no-error situation
// with zero instances returned.
// WBEM_E_INVALID_PROVIDE_REGISTRATION Provider registration for this
// class is incomplete.
// WBEM_E_PROVIDER_NOT_FOUND Provider could not be located. It is not
// registered with us or with COM.
// WBEM_E_PROVIDER_NOT_CAPABLE Provider is not capable of enumerating
// instances.
// WBEM_E_FAILED Unexpected error has occured.
//
//***************************************************************************
HRESULT CWbemNamespace::DynAux_GetInstances(
READONLY CWbemObject *pClassDef,
long lFlags,
IWbemContext* pCtx,
CBasicObjectSink* pSink ,
BOOL bComplexQuery
)
{
// First, get the current task -
// if there isn't one, then we are on an WbemESS thread
// ESS use to issue "internal" queries that are processes without arbitration
CWbemRequest* pCurrReq = CWbemQueue::GetCurrentRequest();
CWmiTask * pCurrTask = pCurrReq?((CWmiTask *)pCurrReq->m_phTask):NULL;
// We'll need the finalizer in case we need to cancel something
HRESULT hr;
_IWmiFinalizer* pMainFnz = NULL;
if (pCurrTask)
{
hr = pCurrTask->GetFinalizer( &pMainFnz );
if (FAILED(hr)) return hr;
}
CReleaseMe rm( pMainFnz );
CWmiMerger* pWmiMerger = NULL;
// Check if query arbitration is enabled
if ( ConfigMgr::GetEnableQueryArbitration() && pCurrTask)
{
// Get the arbitrated query pointer and cast to a merger as appropriate
_IWmiArbitratedQuery* pArbQuery = NULL;
hr = pCurrTask->GetArbitratedQuery( 0L, &pArbQuery );
if ( SUCCEEDED( hr ) )
{
hr = pArbQuery->IsMerger();
if ( SUCCEEDED( hr ) )
{
pWmiMerger = (CWmiMerger*) pArbQuery;
}
else
{
pArbQuery->Release();
}
}
// Clear errors
hr = WBEM_S_NO_ERROR;
} // IF Query arbitration enabled
CReleaseMe rmMerger( (_IWmiArbitratee*) pWmiMerger );
// Perform correct handling based on whether or not we have a merger
if ( pWmiMerger )
{
hr = pWmiMerger->RegisterArbitratedInstRequest( pClassDef, lFlags, pCtx, pSink, bComplexQuery, this );
if (FAILED( hr))
if (pMainFnz) pMainFnz->CancelTask( 0 );
return hr;
}
//
// when the query arbitration is not enabled we fall here
//
CAsyncReq_DynAux_GetInstances * pReq;
pReq = new CAsyncReq_DynAux_GetInstances (this,
pClassDef,
lFlags,
pCtx,
pSink);
if ( pReq == NULL)
{
if (pMainFnz) pMainFnz->CancelTask ( 0 );
return WBEM_E_OUT_OF_MEMORY;
}
if ( NULL == pReq->GetContext() )
{
if (pMainFnz) pMainFnz->CancelTask ( 0 );
delete pReq;
return WBEM_E_OUT_OF_MEMORY;
}
// Set the task for the request - we'll just use the existing one if any
pReq->m_phTask = pCurrTask;
if (pReq->m_phTask) pReq->m_phTask->AddRef();
hr = ConfigMgr::EnqueueRequest(pReq);
if (FAILED(hr))
{
if (pMainFnz) pMainFnz->CancelTask ( 0 );
delete pReq;
}
return hr;
}
//***************************************************************************
//
// CWbemNamespace::DynAux_GetInstances
//
// Gets all instances from the provider specified in the class
// definition. Does no inheritance joins; this is a simple retrieval
// of all instances from the specified class.
//
// Preconditions:
// 1. The class <pClassDef> is known to be marked 'dynamic', but no
// other verification has been done on the class definition.
// 2. <pClassDef> is not NULL.
//
// Postconditions:
// 1. <aInstances> is empty on all error conditions.
//
// PARAMETERS:
//
// READONLY CWbemObject *pClassDef The definition of the class to retrieve
// instances of.
// long lFlags The flags (deep/shallow)
// CFlexArray &aInstances Destination for the instances.
// IWbemClassObject** ppErrorObj Destination for the error object. If
// not NULL, an error object may be placed
// here. It is the caller's responsibility
// to release it if not NULL.
// RETURN VALUES:
//
// WBEM_NO_ERROR No errors. This includes a no-error situation
// with zero instances returned.
// WBEM_E_INVALID_PROVIDE_REGISTRATION Provider registration for this
// class is incomplete.
// WBEM_E_PROVIDER_NOT_FOUND Provider could not be located. It is not
// registered with us or with COM.
// WBEM_E_PROVIDER_NOT_CAPABLE Provider is not capable of enumerating
// instances.
// WBEM_E_FAILED Unexpected error has occured.
//
//***************************************************************************
HRESULT CWbemNamespace::Exec_DynAux_GetInstances(
READONLY CWbemObject *pClassDef,
long lFlags,
IWbemContext* pCtx,
CBasicObjectSink* pSink
)
{
COperationError OpInfo(pSink, L"CreateInstanceEnum", L"", FALSE);
if ( !OpInfo.IsOk() ) return pSink->Return(WBEM_E_OUT_OF_MEMORY);
CVar vProv;
CVar vClassName;
// Get the provider name.
// ======================
try // internal fastprox interfaces throw
{
HRESULT hres = pClassDef->GetQualifier(L"Provider", &vProv);
if (FAILED(hres) || vProv.GetType() != VT_BSTR)
return OpInfo.ErrorOccurred(WBEM_E_INVALID_PROVIDER_REGISTRATION);
if (FAILED(pClassDef->GetClassName(&vClassName)))
return pSink->Return(WBEM_E_OUT_OF_MEMORY);
OpInfo.SetParameterInfo(vClassName.GetLPWSTR());
}
catch(CX_MemoryException &)
{
return pSink->Return(WBEM_E_OUT_OF_MEMORY);
}
// Access Provider Subsystem.
// ==========================
IWbemServices *pProv = 0;
HRESULT hRes;
if (m_pProvFact == NULL)
hRes = WBEM_E_CRITICAL_ERROR;
else
{
WmiInternalContext t_InternalContext ;
ZeroMemory ( & t_InternalContext , sizeof ( t_InternalContext ) );
hRes = m_pProvFact->GetProvider(
t_InternalContext ,
0, // lFlags
pCtx,
0,
m_wszUserName,
m_wsLocale,
0, // IWbemPath pointer
vProv, // Provider
IID_IWbemServices,
(LPVOID *) &pProv);
}
if (FAILED(hRes))
return pSink->Return(hRes);
CReleaseMe _1(pProv);
// Set up the sink chain to be delivered to the provider.
// The code & destruct sequence is critical and the
// refcounting is very carefully thought out. Do not
// change this code unless you know exactly what you are
// doing. And don't even change it then.
// ======================================================
CProviderSink *pProvSink = new CProviderSink(1, vClassName.GetLPWSTR());
if (pProvSink == 0)
return pSink->Return(WBEM_E_OUT_OF_MEMORY);
CReleaseMe _3(pProvSink);
CDecoratingSink * pDecore = new CDecoratingSink(pSink, this);
if (pDecore == NULL)
return pSink->Return(WBEM_E_OUT_OF_MEMORY);
pProvSink->SetNextSink(pDecore);
// Before calling the provider, map the provider to the
// task so that we can cancel it proactively, if required.
// =======================================================
hRes = ((CWmiArbitrator *) m_pArb)->MapProviderToTask(0, pCtx, pProv, pProvSink);
if (FAILED(hRes))
return pSink->Return(hRes);
// Now tell the provider to start enumerating.
hRes = pProv->CreateInstanceEnumAsync(vClassName.GetLPWSTR(),
lFlags & ~WBEM_FLAG_USE_AMENDED_QUALIFIERS,
pCtx,
pProvSink
);
return hRes;
}
//***************************************************************************
//
// CWbemNamespace::DynAux_ExecQueryAsync
//
// Executes a SQL-1 query against a dynamic instance provider for the class
// in the query.
//
// PARAMETERS:
//
// IN DWORD dwNamespace Namespace handle to the current
// namespace (see objdb.h)
// IN CWbemObject* pClassDef Class definition of the class in the
// query. Must be dynamic.
// IN LPWSTR Query The query string.
// IN LPWSTR QueryFormat The query language. Must be WQL.
// IN long lFlags The flags. Not used.
// OUT CFlexArray &aInstances Destinatino for the instances found.
// OUT IWbemClassObject** ppErrorObj Destination for the error object. IF
// not NULL, an error object may be placed
// here. In this case, it is the caller's
// responsibility to release it.
// RETURN VALUES:
//
// WBEM_S_NO_ERROR Success (even though there may not be
// any instances).
// WBEM_E_INVALID_PROVIDE_REGISTRATION Provider registration for this
// class is incomplete.
// WBEM_E_PROVIDER_NOT_FOUND Provider could not be located. It is not
// registered with us or with COM.
// WBEM_E_PROVIDER_NOT_CAPABLE Provider is not capable of enumerating
// instances.
// WBEM_E_FAILED Unexpected error has occured.
//
//***************************************************************************
HRESULT CWbemNamespace::DynAux_ExecQueryAsync (
CWbemObject* pClassDef,
LPWSTR Query,
LPWSTR QueryFormat,
long lFlags,
IWbemContext* pCtx,
CBasicObjectSink* pSink,
BOOL bComplexQuery
)
{
// First, get the current task - if there isn't one, something
// is very wrong.
CWbemRequest* pCurrReq = CWbemQueue::GetCurrentRequest();
_DBG_ASSERT( NULL != pCurrReq && NULL != pCurrReq->m_phTask );
if ( NULL == pCurrReq || NULL == pCurrReq->m_phTask )
{
return WBEM_E_FAILED;
}
// We'll need the finalizer in case we need to cancel something
_IWmiFinalizer* pMainFnz = NULL;
HRESULT hr = ((CWmiTask*) pCurrReq->m_phTask)->GetFinalizer( &pMainFnz );
CReleaseMe rm( pMainFnz );
if ( SUCCEEDED( hr ) )
{
CWmiMerger* pWmiMerger = NULL;
// Check if query arbitration is enabled
if ( ConfigMgr::GetEnableQueryArbitration() )
{
// Get the arbitrated query pointer and cast to a merger as appropriate
_IWmiArbitratedQuery* pArbQuery = NULL;
hr = ((CWmiTask*) pCurrReq->m_phTask)->GetArbitratedQuery( 0L, &pArbQuery );
if ( SUCCEEDED( hr ) )
{
hr = pArbQuery->IsMerger();
if ( SUCCEEDED( hr ) )
{
pWmiMerger = (CWmiMerger*) pArbQuery;
}
else
{
pArbQuery->Release();
}
}
// Clear errors
hr = WBEM_S_NO_ERROR;
} // IF Query arbitration enabled
// Auto cleanup
CReleaseMe rm( (_IWmiArbitratee*) pWmiMerger );
// Perform correct handling based on whether or not we have a merger
if ( NULL != pWmiMerger )
{
hr = pWmiMerger->RegisterArbitratedQueryRequest( pClassDef, lFlags, Query, QueryFormat, pCtx, pSink, this );
if (FAILED(hr))
{
pMainFnz->CancelTask ( 0 );
}
}
else
{
CAsyncReq_DynAux_ExecQueryAsync *pReq = 0;
try
{
pReq = new CAsyncReq_DynAux_ExecQueryAsync (
this,
pClassDef,
Query,
QueryFormat,
lFlags,
pCtx,
pSink
);
}
catch(CX_Exception &)
{
pReq = 0;
}
if (pReq == NULL)
{
pMainFnz->CancelTask ( 0 );
return WBEM_E_OUT_OF_MEMORY;
}
if ( NULL == pReq->GetContext() )
{
pMainFnz->CancelTask ( 0 );
delete pReq;
return WBEM_E_OUT_OF_MEMORY;
}
hr = pReq->Initialize () ;
if ( SUCCEEDED ( hr ) )
{
// Set the task for the request - we'll just use the existing one
pCurrReq->m_phTask->AddRef();
pReq->m_phTask = pCurrReq->m_phTask;
hr = ConfigMgr::EnqueueRequest(pReq);
if (FAILED(hr))
{
pMainFnz->CancelTask ( 0 );
delete pReq;
}
} // IF Request Initialized
else
{
pMainFnz->CancelTask ( 0 );
delete pReq;
}
}
}
return hr;
}
//***************************************************************************
//
// CWbemNamespace::DynAux_ExecQueryAsync
//
// Executes a SQL-1 query against a dynamic instance provider for the class
// in the query.
//
// PARAMETERS:
//
// IN DWORD dwNamespace Namespace handle to the current
// namespace (see objdb.h)
// IN CWbemObject* pClassDef Class definition of the class in the
// query. Must be dynamic.
// IN LPWSTR Query The query string.
// IN LPWSTR QueryFormat The query language. Must be WQL.
// IN long lFlags The flags. Not used.
// OUT CFlexArray &aInstances Destinatino for the instances found.
// OUT IWbemClassObject** ppErrorObj Destination for the error object. IF
// not NULL, an error object may be placed
// here. In this case, it is the caller's
// responsibility to release it.
// RETURN VALUES:
//
// WBEM_S_NO_ERROR Success (even though there may not be
// any instances).
// WBEM_E_INVALID_PROVIDE_REGISTRATION Provider registration for this
// class is incomplete.
// WBEM_E_PROVIDER_NOT_FOUND Provider could not be located. It is not
// registered with us or with COM.
// WBEM_E_PROVIDER_NOT_CAPABLE Provider is not capable of enumerating
// instances.
// WBEM_E_FAILED Unexpected error has occured.
//
//***************************************************************************
HRESULT CWbemNamespace::Exec_DynAux_ExecQueryAsync (
CWbemObject* pClassDef,
LPWSTR Query,
LPWSTR QueryFormat,
long lFlags,
IWbemContext* pCtx,
CBasicObjectSink* pSink
)
{
COperationError OpInfo(pSink, L"ExecQuery", Query, FALSE);
if (! OpInfo.IsOk()) return pSink->Return(WBEM_E_OUT_OF_MEMORY);
// Get the provider name.
// ======================
CVar vProv;
HRESULT hres = pClassDef->GetQualifier(L"Provider", &vProv);
if (FAILED(hres) || vProv.GetType() != VT_BSTR)
return OpInfo.ErrorOccurred(WBEM_E_INVALID_PROVIDER_REGISTRATION);
// Access the provider cache.
// ==========================
IWbemServices *pProv = 0;
HRESULT hRes;
if(m_pProvFact == NULL)
hRes = WBEM_E_CRITICAL_ERROR;
else
{
WmiInternalContext t_InternalContext ;
ZeroMemory ( & t_InternalContext , sizeof ( t_InternalContext ) ) ; // SEC:REVIEWED 2002-03-22 : OK
hRes = m_pProvFact->GetProvider(
t_InternalContext ,
0, // lFlags
pCtx,
0,
m_wszUserName,
m_wsLocale,
0, // IWbemPath pointer
vProv, // Provider
IID_IWbemServices,
(LPVOID *) &pProv
);
}
if (FAILED(hRes))
{
return pSink->Return(hRes);
}
CReleaseMe _1(pProv);
// Set up the sink chain to be delivered to the provider.
// The code & destruct sequence is critical and the
// refcounting is very carefully thought out. Do not
// change this code unless you know exactly what you are
// doing. And don't even change it then.
// ======================================================
CProviderSink *pProvSink = new CProviderSink(1, Query);
if (pProvSink == 0)
return pSink->Return(WBEM_E_OUT_OF_MEMORY);
CReleaseMe _3(pProvSink);
CDecoratingSink * pDecore = new CDecoratingSink(pSink, this);
if (pDecore == NULL)
return pSink->Return(WBEM_E_OUT_OF_MEMORY);
pProvSink->SetNextSink(pDecore);
// Before calling the provider, map the provider to the
// task so that we can cancel it proactively, if required.
// =======================================================
hRes = ((CWmiArbitrator *) m_pArb)->MapProviderToTask(0, pCtx, pProv, pProvSink);
if (FAILED(hRes))
return pSink->Return(hRes);
// Now tell the provider to start enumerating.
hRes = pProv->ExecQueryAsync(QueryFormat,
Query, lFlags& ~WBEM_FLAG_USE_AMENDED_QUALIFIERS,
pCtx, pProvSink);
return hRes;
}
//***************************************************************************
//
// CWbemNamespace::DynAux_ExecQueryAsync
//
// Executes a SQL-1 query against a dynamic instance provider for the class
// in the query.
//
// PARAMETERS:
//
// IN DWORD dwNamespace Namespace handle to the current
// namespace (see objdb.h)
// IN CWbemObject* pClassDef Class definition of the class in the
// query. Must be dynamic.
// IN LPWSTR Query The query string.
// IN LPWSTR QueryFormat The query language. Must be WQL.
// IN long lFlags The flags. Not used.
// OUT CFlexArray &aInstances Destinatino for the instances found.
// OUT IWbemClassObject** ppErrorObj Destination for the error object. IF
// not NULL, an error object may be placed
// here. In this case, it is the caller's
// responsibility to release it.
// RETURN VALUES:
//
// WBEM_S_NO_ERROR Success (even though there may not be
// any instances).
// WBEM_E_INVALID_PROVIDE_REGISTRATION Provider registration for this
// class is incomplete.
// WBEM_E_PROVIDER_NOT_FOUND Provider could not be located. It is not
// registered with us or with COM.
// WBEM_E_PROVIDER_NOT_CAPABLE Provider is not capable of enumerating
// instances.
// WBEM_E_FAILED Unexpected error has occured.
//
//***************************************************************************
HRESULT CWbemNamespace::DynAux_ExecQueryExtendedAsync(
LPWSTR wsProvider,
LPWSTR Query,
LPWSTR QueryFormat,
long lFlags,
IWbemContext* pCtx,
CComplexProjectionSink* pSink
)
{
COperationError OpInfo(pSink, L"ExecQuery", Query, FALSE);
if ( !OpInfo.IsOk() ) return WBEM_E_OUT_OF_MEMORY;
// Access the provider cache.
// ==========================
IWbemServices *pProv = 0;
HRESULT hRes;
if(m_pProvFact == NULL)
hRes = WBEM_E_CRITICAL_ERROR;
else
{
WmiInternalContext t_InternalContext ;
ZeroMemory ( & t_InternalContext , sizeof ( t_InternalContext ) ) ; // SEC:REVIEWED 2002-03-22 : OK
hRes = m_pProvFact->GetProvider(
t_InternalContext ,
0, // lFlags
pCtx,
0,
m_wszUserName,
m_wsLocale,
0, // IWbemPath pointer
wsProvider, // provider name
IID_IWbemServices,
(LPVOID *) &pProv
);
}
if (FAILED(hRes))
{
return pSink->Return(hRes);
}
CReleaseMe _(pProv);
_IWmiProviderConfiguration *t_Configuration = NULL ;
hRes = pProv->QueryInterface ( IID__IWmiProviderConfiguration , ( void ** ) & t_Configuration ) ;
if ( SUCCEEDED ( hRes ) )
{
CReleaseMe _1(t_Configuration);
VARIANT t_Variant ;
VariantInit ( & t_Variant ) ;
hRes = t_Configuration->Query (
this ,
lFlags& ~WBEM_FLAG_USE_AMENDED_QUALIFIERS ,
pCtx ,
WBEM_PROVIDER_CONFIGURATION_CLASS_ID_INSTANCE_PROVIDER_REGISTRATION ,
WBEM_PROVIDER_CONFIGURATION_PROPERTY_ID_EXTENDEDQUERY_SUPPORT ,
& t_Variant
) ;
if ( SUCCEEDED ( hRes ) )
{
if ( t_Variant.boolVal == VARIANT_TRUE )
{
CDecoratingSink * pDecore = new CDecoratingSink(pSink, this);
if(pDecore == NULL)
return pSink->Return(WBEM_E_OUT_OF_MEMORY);
pDecore->AddRef();
CReleaseMe cdecor(pDecore);
hRes = pProv->ExecQueryAsync(QueryFormat, Query, lFlags& ~WBEM_FLAG_USE_AMENDED_QUALIFIERS, pCtx, pDecore);
}
else
{
hRes = WBEM_E_INVALID_QUERY ;
}
VariantClear ( & t_Variant ) ;
}
else
{
hRes = WBEM_E_UNEXPECTED ;
}
}
else
{
hRes = WBEM_E_UNEXPECTED ;
}
return hRes;
}
//***************************************************************************
//
// CWbemNamespace::Static_QueryRepository
//
// Performs query against the repository. This only happens if there is an
// associated task. If not, then we execute the query on the same thread.
//
// PARAMETERS:
//
// READONLY CWbemObject *pClassDef The definition of the class to retrieve
// instances of.
// long lFlags The flags (deep/shallow)
//
// RETURN VALUES:
//
// WBEM_NO_ERROR No errors. This includes a no-error situation
// with zero instances returned.
// WBEM_E_INVALID_PROVIDE_REGISTRATION Provider registration for this
// class is incomplete.
// WBEM_E_PROVIDER_NOT_FOUND Provider could not be located. It is not
// registered with us or with COM.
// WBEM_E_PROVIDER_NOT_CAPABLE Provider is not capable of enumerating
// instances.
// WBEM_E_FAILED Unexpected error has occured.
//
//***************************************************************************
HRESULT CWbemNamespace::Static_QueryRepository(
READONLY CWbemObject *pClassDef,
long lFlags,
IWbemContext* pCtx,
CBasicObjectSink* pSink ,
QL_LEVEL_1_RPN_EXPRESSION* pParsedQuery,
LPCWSTR pwszClassName,
CWmiMerger* pWmiMerger
)
{
HRESULT hr = WBEM_S_NO_ERROR;
// First, get the current task and request. If there isn't one, we're most
// likely being called on an ESS callback, and will just perform the call on
// this thread.
CWbemRequest* pCurrReq = CWbemQueue::GetCurrentRequest();
if ( NULL != pCurrReq && NULL != pCurrReq->m_phTask &&
ConfigMgr::GetEnableQueryArbitration() )
{
// We'll need the finalizer in case we need to cancel something
_IWmiFinalizer* pMainFnz = NULL;
HRESULT hr = ((CWmiTask*) pCurrReq->m_phTask)->GetFinalizer( &pMainFnz );
CReleaseMe rm( pMainFnz );
if ( SUCCEEDED( hr ) )
{
//
// creates the CMergerDynReq_Static_GetInstances
// creates the Merger Request Manager
// adds the request to the Request Manager
//
hr = pWmiMerger->RegisterArbitratedStaticRequest( pClassDef, lFlags, pCtx, pSink, this, pParsedQuery );
if (FAILED(hr))
{
pMainFnz->CancelTask ( 0 );
}
} // IF Got Finalizer
// In the case of an error we should do a setstatus of the error. Otherwise, the setstatus will occur
// when the new request is processed.
if ( FAILED( hr ) )
{
pSink->SetStatus( 0L, hr, 0L, NULL );
}
}
else
{
// If we're here, then we should disallow merger specific throttling since
// this request is happening through an internal thread without following
// the request/task hierarchy, meaning that there shouldn't be a hierarchy
// we need to worry about for this class, so don't let the merger do any
// internal throttling
pWmiMerger->EnableMergerThrottling( false );
int nRes = CQueryEngine::ExecAtomicDbQuery(
GetNsSession(),
GetNsHandle(),
GetScope(),
pwszClassName,
pParsedQuery,
pSink,
this );
if (nRes == CQueryEngine::invalid_query)
hr = WBEM_E_INVALID_QUERY;
else if(nRes != 0)
hr = WBEM_E_FAILED;
else
hr = WBEM_S_NO_ERROR;
pSink->SetStatus( 0L, hr, 0L, NULL );
}
return hr;
}
//***************************************************************************
//
// CWbemNamespace::DecorateObject
//
// Sets the origin information on a given object to reflect this namespace
// and this server. See CWbemObject::Decorate in fastobj.h for details.
// THIS FUNCTION CAN ONLY DECORATE CWbemObject POINTERS, NOT OTHER PEOPLE'S
// IMPLEMENTATIONS of IWbemClassObject.
//
// PARAMETERS:
//
// IWbemClassObject* pObject The object to decorate.
//
// RETURN VALUES:
//
// WBEM_S_NO_ERROR Success
// WBEM_E_INVALID_PARAMETER pObject == NULL.
//
//***************************************************************************
HRESULT CWbemNamespace::DecorateObject(IWbemClassObject* pObject)
{
if(pObject == NULL)
return WBEM_E_INVALID_PARAMETER;
return ((CWbemObject*)pObject)->Decorate(ConfigMgr::GetMachineName(),
m_pThisNamespace);
}
//***************************************************************************
//
//***************************************************************************
typedef std::vector<CDynasty*, wbem_allocator<CDynasty*> > CDynastyPtrArray;
typedef std::map<LPWSTR, CDynasty*, wcsiless, wbem_allocator<CDynasty*> > CCDynastyMap;
HRESULT AddAllMembers(CDynasty* pDynasty, CCDynastyMap& Map)
{
// Catch any exceptions the allocator might throw
try
{
Map[pDynasty->m_wszClassName] = pDynasty;
}
catch(CX_MemoryException &)
{
return WBEM_E_OUT_OF_MEMORY;
}
HRESULT hr = WBEM_S_NO_ERROR;
CFlexArray* pChildren = &pDynasty->m_Children;
for(int i = 0; SUCCEEDED(hr) && i < pChildren->Size(); i++)
{
hr = AddAllMembers((CDynasty*)pChildren->GetAt(i), Map);
}
return hr;
}
//***************************************************************************
//
// CWbemNamespace::DynAux_BuildClassHierarchy
//
// Recursively builds the hierarchy of classes derived from a given one.
// The structure used to represent the hierarchy -- CDynasty is described
// in objdb.h
//
// PARAMETERS:
//
// IN LPWSTR wszClassName The name of the parent class.
// IN LONG lFlags If SHALLOW, just the class itself is
// returned. If DEEP, recursive enumeration
// is performed.
// OUT CDynasty** ppDynasty Destination for the tree. The caller must
// delete the pointer on success.
//
// RETURN VALUES:
//
// WBEM_S_NO_ERROR Success
// Any of the return values returned by GetObject or CreateClassEnum,
// as documented in the help file.
//
//***************************************************************************
HRESULT CWbemNamespace::DynAux_BuildClassHierarchy(
IN LPWSTR wszClassName,
IN LONG lFlags,
IN IWbemContext* pCtx,
OUT wmilib::auto_ptr<CDynasty> & pDynasty,
OUT IWbemClassObject** ppErrorObj)
{
HRESULT hres;
*ppErrorObj = NULL;
// Get the list of classes from all class providers
// ================================================
CSynchronousSink* pSyncSink = CSynchronousSink::Create();
if(pSyncSink == NULL) return WBEM_E_OUT_OF_MEMORY;
pSyncSink->AddRef();
CReleaseMe rm1(pSyncSink);
hres = Exec_CreateClassEnum(wszClassName,
lFlags | WBEM_FLAG_NO_STATIC,
pCtx,
pSyncSink);
pSyncSink->Block();
pSyncSink->GetStatus(&hres, NULL, ppErrorObj);
if(FAILED(hres))
return hres;
// Get the static dynasty
// ======================
wmilib::auto_ptr<CDynasty> pMainDynasty;
HRESULT hRes = CRepository::BuildClassHierarchy(m_pSession,
m_pNsHandle,
wszClassName,
lFlags & WBEM_MASK_DEPTH,
pMainDynasty);
if (hRes == WBEM_E_NOT_FOUND)
{
IWbemClassObject* pObj;
HRESULT hres = Exec_GetObjectByPath(wszClassName, lFlags, pCtx,
&pObj,
ppErrorObj);
if(FAILED(hres)) return hres;
CReleaseMe rmClassObj(pObj);
pMainDynasty.reset(CDynasty::Create(pObj));
if(NULL == pMainDynasty.get()) return WBEM_E_OUT_OF_MEMORY;
if(pMainDynasty->m_pClassObj == NULL)
{
ERRORTRACE((LOG_WBEMCORE, "Provider returned invalid class for %S\n",wszClassName));
return WBEM_E_PROVIDER_FAILURE;
}
hRes = S_OK;
}
if (FAILED(hRes)) return hRes;
CRefedPointerArray<IWbemClassObject> &rProvidedClasses = pSyncSink->GetObjects();
// Create a map of class names to their dynasties
// ==============================================
CCDynastyMap mapClasses;
hres = AddAllMembers(pMainDynasty.get(), mapClasses);
if ( FAILED(hres)) return hres;
CDynastyPtrArray aProvidedDyns;
try
{
aProvidedDyns.reserve(rProvidedClasses.GetSize());
}
catch(CX_MemoryException &)
{
return WBEM_E_OUT_OF_MEMORY;
}
for(int i = 0; i < rProvidedClasses.GetSize(); i++)
{
CDynasty* pNew = CDynasty::Create(rProvidedClasses[i]);
if(pNew == NULL)
return WBEM_E_OUT_OF_MEMORY;
if(pNew->m_pClassObj == NULL)
{
delete pNew;
ERRORTRACE((LOG_WBEMCORE, "Provider returned invalid class!\n"));
continue;
}
// The vector or the map may throw exceptions
try
{
mapClasses[pNew->m_wszClassName] = pNew;
aProvidedDyns.push_back(pNew);
}
catch(CX_MemoryException &)
{
return WBEM_E_OUT_OF_MEMORY;
}
}
// Go through it once and add all classes to their parent's dynasty
// ================================================================
for(CDynastyPtrArray::iterator it = aProvidedDyns.begin();
it != aProvidedDyns.end(); it++)
{
CDynasty* pDyn = *it;
CVar vParent;
CWbemObject *pObj = (CWbemObject *) pDyn->m_pClassObj;
if(FAILED(pObj->GetSuperclassName(&vParent)) ||
vParent.IsNull())
{
ERRORTRACE((LOG_WBEMCORE,"Provider returned top-level class %S as a child "
"of %S\n", pDyn->m_wszClassName, wszClassName));
continue;
}
CCDynastyMap::iterator itParent =
mapClasses.find(vParent.GetLPWSTR());
if((itParent == mapClasses.end()))
{
if(wbem_wcsicmp(pDyn->m_wszClassName, wszClassName))
{
ERRORTRACE((LOG_WBEMCORE,"Provider returned class %S without parent!\n",
vParent.GetLPWSTR()));
}
continue;
}
CDynasty* pParentDyn = itParent->second;
pParentDyn->AddChild(pDyn);
}
// Build the chain up to the highest keyed parent
// ==============================================
pDynasty = pMainDynasty;
hres = DynAux_BuildChainUp( pCtx, pDynasty, ppErrorObj);
return hres;
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWbemNamespace::DynAux_BuildChainUp( IN IWbemContext* pCtx,
OUT wmilib::auto_ptr<CDynasty> & pTop,
OUT IWbemClassObject** ppErrorObj)
{
*ppErrorObj = NULL;
// Go up while there is a key at this level and we are dynamic
// ===========================================================
while( pTop->IsDynamic() && pTop->IsKeyed())
{
CVar vParentName;
CWbemObject *pObj = (CWbemObject *) pTop->m_pClassObj;
if(FAILED(pObj->GetSuperclassName(&vParentName)) ||
vParentName.IsNull())
{
// Top level --- time to quit
// ==========================
return WBEM_S_NO_ERROR;
}
IWbemClassObject* pParent;
HRESULT hres = Exec_GetObjectByPath(vParentName.GetLPWSTR(), 0,pCtx,&pParent, ppErrorObj);
if(FAILED(hres))
return hres;
if(pParent == NULL)
return WBEM_E_PROVIDER_FAILURE;
// SJS - Amendment is the same as Abstract
if(!((CWbemClass*)pParent)->IsKeyed() ||
((CWbemClass*)pParent)->IsAbstract() ||
((CWbemClass*)pParent)->IsAmendment() )
{
// We are it
// =========
pParent->Release();
return WBEM_S_NO_ERROR;
}
// Extend the dynasty by this class
// ================================
wmilib::auto_ptr<CDynasty> pNew( CDynasty::Create(pParent));
if (NULL == pNew.get()) return WBEM_E_OUT_OF_MEMORY;
pParent->Release();
if(pNew->m_pClassObj == NULL)
{
return WBEM_E_PROVIDER_FAILURE;
}
pNew->AddChild(pTop.get());
pTop.release();
pTop.reset(pNew.release());
}
return WBEM_S_NO_ERROR;
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWbemNamespace::IsPutRequiredForClass(CWbemClass* pClass,
CWbemInstance* pInst, IWbemContext* pCtx,
BOOL bParentTakenCareOf)
{
HRESULT hres;
// Get the per-property put information out of the context
// =======================================================
BOOL bRestrictedPut = FALSE;
BOOL bStrictNulls = FALSE;
BOOL bPropertyList = FALSE;
CWStringArray awsProperties;
hres = GetContextPutExtensions(pCtx, bRestrictedPut, bStrictNulls,
bPropertyList, awsProperties);
if(FAILED(hres))
return hres;
if(bRestrictedPut && bStrictNulls && !bPropertyList)
{
// All properties must be put, even the NULL ones
// ==============================================
return WBEM_S_NO_ERROR;
}
// Enumerate all properties of the class
// =====================================
long lEnumFlags = 0;
if(bParentTakenCareOf)
{
// Only look at local (non-propagated) properties
// ==============================================
lEnumFlags = WBEM_FLAG_LOCAL_ONLY;
}
else
{
// We are in charge of our parent's properties
// ===========================================
lEnumFlags = WBEM_FLAG_NONSYSTEM_ONLY;
}
pClass->BeginEnumeration(lEnumFlags);
BSTR strName = NULL;
while((hres = pClass->Next(0, &strName, NULL, NULL, NULL)) == S_OK)
{
hres = DoesNeedToBePut(strName, pInst, bRestrictedPut,
bStrictNulls, bPropertyList, awsProperties);
SysFreeString(strName);
if(hres == WBEM_S_NO_ERROR)
{
// Found a needed property
// =======================
return WBEM_S_NO_ERROR;
}
if(FAILED(hres))
return hres;
}
// No properties of this class need to be put
// ==========================================
return WBEM_S_FALSE;
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWbemNamespace::DoesNeedToBePut(LPCWSTR wszName, CWbemInstance* pInst,
BOOL bRestrictedPut, BOOL bStrictNulls, BOOL bPropertyList,
CWStringArray& awsProperties)
{
HRESULT hres;
// Check if the property is a key
// ==============================
CVar vKey;
pInst->GetPropQualifier((LPWSTR)wszName, L"key", &vKey);
if(vKey.GetType() == VT_BOOL && vKey.GetBool())
{
// It's a key --- no such thing as updating its value, and this code
// only applies to updates.
// =================================================================
return WBEM_S_FALSE;
}
// Determine if NULLness and or membership in the list play any role
// =================================================================
BOOL bCheckNullness = FALSE;
BOOL bCheckMembership = FALSE;
if(bRestrictedPut)
{
bCheckNullness = !bStrictNulls;
bCheckMembership = bPropertyList;
}
else
{
bCheckNullness = TRUE;
bCheckMembership = FALSE;
}
// Check NULLness and/or membership if required
// ============================================
BOOL bNullnessChecked = FALSE;
BOOL bMembershipChecked = FALSE;
if(bCheckNullness)
{
CVar vVal;
hres = pInst->GetNonsystemPropertyValue((LPWSTR)wszName, &vVal);
if(FAILED(hres))
return hres;
bNullnessChecked = !vVal.IsNull();
}
else
bNullnessChecked = TRUE;
if(bCheckMembership)
{
int nIndex = awsProperties.FindStr(wszName, CWStringArray::no_case);
bMembershipChecked = (nIndex >= 0);
}
else
bMembershipChecked = TRUE;
// Make sure that both NULLness and membership either checked out or were
// not required
// ======================================================================
if(bMembershipChecked && bNullnessChecked)
{
return WBEM_S_NO_ERROR;
}
else
{
return WBEM_S_FALSE;
}
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWbemNamespace::GetContextPutExtensions(IWbemContext* pCtx,
BOOL& bRestrictedPut, BOOL& bStrictNulls, BOOL& bPropertyList,
CWStringArray& awsProperties)
{
HRESULT hres;
if(pCtx == NULL)
{
//
// Default is: no restructions, which makes the rest of the properties
// irrelevant
//
bRestrictedPut = FALSE;
return WBEM_S_NO_ERROR;
}
// Initialize out-params
// =====================
bRestrictedPut = FALSE;
bStrictNulls = FALSE;
bPropertyList = FALSE;
awsProperties.Empty();
// Check if the context is even present
// ====================================
if(pCtx == NULL)
return WBEM_S_NO_ERROR;
// Check if put extensions are specified
// =====================================
hres = GetContextBoolean(pCtx, L"__PUT_EXTENSIONS", &bRestrictedPut);
if(FAILED(hres)) return hres;
if(!bRestrictedPut)
return WBEM_S_NO_ERROR;
// Check if NULLs are strict
// =========================
hres = GetContextBoolean(pCtx, L"__PUT_EXT_STRICT_NULLS",
&bStrictNulls);
if(FAILED(hres)) return hres;
// Check if the list of properties is available
// ============================================
VARIANT v;
VariantInit(&v);
CClearMe cm1(&v);
hres = pCtx->GetValue(L"__PUT_EXT_PROPERTIES", 0, &v);
if(FAILED(hres))
{
if(hres == WBEM_E_NOT_FOUND)
{
return WBEM_S_NO_ERROR;
}
else
{
ERRORTRACE((LOG_WBEMCORE, "Error retrieving list of properties "
"from context: %X\n", hres));
return hres;
}
}
if(V_VT(&v) != (VT_BSTR | VT_ARRAY))
{
ERRORTRACE((LOG_WBEMCORE, "Invalid type is used for "
"the list of properties in the context: must be "
"string array. The value will be ignored\n"));
return WBEM_S_NO_ERROR;
}
bPropertyList = TRUE;
// Transfer property names to the array
// ====================================
CSafeArray saProperties(V_ARRAY(&v), VT_BSTR,
CSafeArray::no_delete | CSafeArray::bind);
for(int i = 0; i < saProperties.Size(); i++)
{
BSTR strProp = saProperties.GetBSTRAt(i);
CSysFreeMe sfm(strProp);
if (strProp)
{
if (CFlexArray::no_error != awsProperties.Add(strProp))
return WBEM_E_OUT_OF_MEMORY;
}
}
return WBEM_S_NO_ERROR;
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWbemNamespace::GetContextBoolean(IWbemContext* pCtx,
LPCWSTR wszName, BOOL* pbValue)
{
HRESULT hres;
*pbValue = FALSE;
//
// NULL context means "FALSE"
//
if(pCtx == NULL)
return WBEM_S_NO_ERROR;
VARIANT v;
VariantInit(&v);
CClearMe cm1(&v);
hres = pCtx->GetValue((LPWSTR)wszName, 0, &v);
if(FAILED(hres))
{
if(hres == WBEM_E_NOT_FOUND)
{
return WBEM_S_NO_ERROR;
}
else
{
ERRORTRACE((LOG_WBEMCORE, "Error retrieving context property %S:"
" %X\n", wszName, hres));
return hres;
}
}
if(V_VT(&v) != VT_BOOL)
{
ERRORTRACE((LOG_WBEMCORE, "Invalid type is used for "
"%S property of the context: must be "
"boolean. The value will be ignored\n", wszName));
return WBEM_S_NO_ERROR;
}
if(V_BOOL(&v) != VARIANT_TRUE)
{
return WBEM_S_NO_ERROR;
}
*pbValue = TRUE;
return WBEM_S_NO_ERROR;
}
//***************************************************************************
//
//***************************************************************************
STDMETHODIMP CWbemNamespace::FindKeyRoot(LPCWSTR wszClassName,
IWbemClassObject** ppKeyRootClass)
{
//
// Check if the namespace is still valid (returns if not)
//
HRESULT hRes = CheckNs();
if (FAILED(hRes))
return hRes;
//
// Call on the database to do the job
//
hRes = CRepository::FindKeyRoot(m_pSession, m_pNsHandle, wszClassName, ppKeyRootClass);
return hRes;
}
//***************************************************************************
//
//***************************************************************************
STDMETHODIMP CWbemNamespace::GetNormalizedPath( BSTR pstrPath,
BSTR* pstrStandardPath )
{
//
// Check if the namespace is still valid (returns if not)
//
HRESULT hRes = CheckNs();
if (FAILED(hRes))
return hRes;
//
// check parameters.
//
if ( NULL == pstrPath || NULL == pstrStandardPath )
{
return WBEM_E_INVALID_PARAMETER;
}
HRESULT hres;
*pstrStandardPath = NULL;
// Parse it
// ========
CObjectPathParser Parser;
ParsedObjectPath* pPath;
int nRes = Parser.Parse(pstrPath, &pPath);
if( nRes != CObjectPathParser::NoError )
{
return WBEM_E_INVALID_OBJECT_PATH;
}
CDeleteMe<ParsedObjectPath> dm(pPath);
//
// Figure out the class that defined the key
//
IWbemClassObject* pKeyRootClass = NULL;
hres = FindKeyRoot(pPath->m_pClass, &pKeyRootClass);
if(FAILED(hres))
{
return hres;
}
CReleaseMe rm(pKeyRootClass);
_IWmiObject* pWmiObject = NULL;
hres = pKeyRootClass->QueryInterface(IID__IWmiObject, (void**)&pWmiObject);
if(FAILED(hres))
{
return hres;
}
CReleaseMe rm1(pWmiObject);
long lHandle = 0L;
ULONG uFlags = 0L;
WCHAR wszClassName[64];
DWORD dwBuffSize = 64;
DWORD dwBuffUsed = 0;
BOOL fNull = FALSE;
LPWSTR pwszName = wszClassName;
LPWSTR pwszDelete = NULL;
// Try to read in the class name. Allocate a buffer if we have to.
hres = pWmiObject->ReadProp( L"__CLASS", 0L, dwBuffSize, NULL, NULL, &fNull, &dwBuffUsed, pwszName );
if ( FAILED( hres ) )
{
if ( WBEM_E_BUFFER_TOO_SMALL == hres )
{
pwszName = new WCHAR[dwBuffUsed/2];
if ( NULL == pwszName )
{
return WBEM_E_OUT_OF_MEMORY;
}
else
{
dwBuffSize = dwBuffUsed;
// Try to read in the class name. Allocate a buffer if we have to.
hres = pWmiObject->ReadProp( L"__CLASS", 0L, dwBuffSize, NULL, NULL, &fNull, &dwBuffUsed, pwszName );
if ( FAILED( hres ) )
{
delete [] pwszName;
return hres;
}
// Allows for scoped cleanup only if we alloctaed something
pwszDelete = pwszName;
}
}
else
{
return hres;
}
}
//
// Ensures proper cleanup. If we didn't allocate a buffer to delete,
// this pointer will be NULL.
//
CVectorDeleteMe<WCHAR> vdm1(pwszDelete);
// oop
if ( fNull )
{
return WBEM_E_INVALID_OPERATION;
}
//
// want to normalize out the single key prop exception
//
if ( pPath->m_dwNumKeys == 1 )
{
delete pPath->m_paKeys[0]->m_pName;
pPath->m_paKeys[0]->m_pName = NULL;
}
//
// set the normalized class on the path if different
// than the one in the path.
//
if ( wbem_wcsicmp( pPath->m_pClass, pwszName ) != 0 )
{
if ( !pPath->SetClassName( pwszName ) )
{
return WBEM_E_OUT_OF_MEMORY;
}
}
//
// now unparse the normalized path
//
LPWSTR wszNormPath;
nRes = CObjectPathParser::Unparse( pPath, &wszNormPath );
if ( nRes != CObjectPathParser::NoError )
{
return WBEM_E_OUT_OF_MEMORY;
}
*pstrStandardPath = SysAllocString( wszNormPath );
delete wszNormPath;
return *pstrStandardPath != NULL ? WBEM_S_NO_ERROR : WBEM_E_OUT_OF_MEMORY;
}
class CRevertCallSec
{
BOOL m_bEnabled;
IUnknown * m_pCallSec;
public:
CRevertCallSec(BOOL bEnabled,IUnknown * pCallSec):
m_bEnabled(bEnabled),
m_pCallSec(pCallSec){};
~CRevertCallSec(){
if (m_bEnabled){
IUnknown * pOld = NULL;
CoSwitchCallContext(m_pCallSec,&pOld);
}
};
};
//***************************************************************************
//
//***************************************************************************
STDMETHODIMP CWbemNamespace::InternalGetClass(
LPCWSTR wszClassName,
IWbemClassObject** ppClass)
{
if (g_bDontAllowNewConnections || m_bShutDown)
{
return WBEM_E_SHUTTING_DOWN;
}
IWbemContext *pContext = NULL ;
CWbemRequest* pReq = CWbemQueue::GetCurrentRequest() ;
if (pReq == NULL)
{
pContext = ConfigMgr::GetNewContext();
if ( pContext == NULL )
return WBEM_E_OUT_OF_MEMORY;
}
else
{
pContext = pReq->GetContext();
pContext->AddRef () ; //for CReleaseMe
}
CReleaseMe _1_pContext (pContext) ;
HRESULT hr;
// determine if there is a call context. If there is, then we
// dont do anything.
IServerSecurity * pSec = NULL;
IWbemCallSecurity * pCallSec = NULL;
IUnknown * pOld = NULL, *pNew = NULL;
hr = CoGetCallContext(IID_IServerSecurity, (void**)&pSec);
if(SUCCEEDED(hr))
{
pSec->Release();
}
else
{
// provider subsystem needs a call context, so create on
pCallSec = CWbemCallSecurity::CreateInst();
if(pCallSec == NULL)
return WBEM_E_OUT_OF_MEMORY;
}
CReleaseMe rm(pCallSec);
// initialize call security for provider sub system
if(pCallSec)
{
hr = pCallSec->CloneThreadContext(TRUE);
if(FAILED(hr))
return hr;
hr = CoSwitchCallContext(pCallSec, &pOld);
if(FAILED(hr))
return hr;
}
CRevertCallSec Revert(pCallSec?TRUE:FALSE,pOld); // SEC:REVIEWED 2002-03-22 : Assumes success; why is this here? It is the only occurrence.
hr = Exec_GetObjectByPath((LPWSTR)wszClassName, 0, pContext, ppClass, NULL);
return hr;
}
//***************************************************************************
//
//***************************************************************************
STDMETHODIMP CWbemNamespace::InternalGetInstance(
LPCWSTR wszPath,
IWbemClassObject** ppInstance)
{
if (g_bDontAllowNewConnections || m_bShutDown)
{
return WBEM_E_SHUTTING_DOWN;
}
IWbemContext *pContext = NULL ;
CWbemRequest* pReq = CWbemQueue::GetCurrentRequest() ;
if (pReq == NULL)
{
pContext = ConfigMgr::GetNewContext();
if ( pContext == NULL )
return WBEM_E_OUT_OF_MEMORY;
}
else
{
pContext = pReq->GetContext();
pContext->AddRef () ; //for CReleaseMe
}
CReleaseMe _1_pContext (pContext) ;
return Exec_GetObjectByPath((LPWSTR)wszPath, 0, pContext, ppInstance, NULL);
}
//***************************************************************************
//
//***************************************************************************
STDMETHODIMP CWbemNamespace::InternalExecQuery(
LPCWSTR wszQueryLanguage,
LPCWSTR wszQuery,
long lFlags,
IWbemObjectSink* pSink)
{
if (g_bDontAllowNewConnections || m_bShutDown)
{
return WBEM_E_SHUTTING_DOWN;
}
IWbemContext *pContext = NULL ;
CWbemRequest* pReq = CWbemQueue::GetCurrentRequest() ;
if (pReq == NULL)
{
pContext = ConfigMgr::GetNewContext();
if ( pContext == NULL )
return WBEM_E_OUT_OF_MEMORY;
}
else
{
pContext = pReq->GetContext();
pContext->AddRef () ; //for CReleaseMe
}
CReleaseMe _1_pContext (pContext) ;
CSimpleWrapperSink ws(pSink);
return CQueryEngine::ExecQuery(this, (LPWSTR)wszQueryLanguage,
(LPWSTR)wszQuery, lFlags, pContext, &ws);
}
//***************************************************************************
//
//***************************************************************************
STDMETHODIMP CWbemNamespace::InternalCreateInstanceEnum(
LPCWSTR wszClassName,
long lFlags,
IWbemObjectSink* pSink)
{
if (g_bDontAllowNewConnections || m_bShutDown)
{
return WBEM_E_SHUTTING_DOWN;
}
IWbemContext *pContext = NULL ;
CWbemRequest* pReq = CWbemQueue::GetCurrentRequest() ;
if (pReq == NULL)
{
pContext = ConfigMgr::GetNewContext();
if ( pContext == NULL )
return WBEM_E_OUT_OF_MEMORY;
}
else
{
pContext = pReq->GetContext();
pContext->AddRef () ; //for CReleaseMe
}
CReleaseMe _1_pContext (pContext) ;
CSimpleWrapperSink ws(pSink);
return Exec_CreateInstanceEnum((LPWSTR)wszClassName, lFlags, pContext, &ws);
}
//***************************************************************************
//
//***************************************************************************
STDMETHODIMP CWbemNamespace::InternalPutInstance(
IWbemClassObject* pInst)
{
if (g_bDontAllowNewConnections || m_bShutDown)
{
return WBEM_E_SHUTTING_DOWN;
}
IWbemContext *pContext = NULL ;
CWbemRequest* pReq = CWbemQueue::GetCurrentRequest() ;
if (pReq == NULL)
{
pContext = ConfigMgr::GetNewContext();
if ( pContext == NULL )
return WBEM_E_OUT_OF_MEMORY;
}
else
{
pContext = pReq->GetContext();
pContext->AddRef () ; //for CReleaseMe
}
CReleaseMe _1_pContext (pContext) ;
CSynchronousSink* pSink = CSynchronousSink::Create();
if(pSink == NULL) return WBEM_E_OUT_OF_MEMORY;
pSink->AddRef();
CReleaseMe rm1(pSink);
Exec_PutInstance(pInst, 0, pContext, pSink);
HRESULT hres = WBEM_E_CRITICAL_ERROR;
pSink->GetStatus(&hres, NULL, NULL);
return hres;
}
//***************************************************************************
//
//***************************************************************************
STDMETHODIMP CWbemNamespace::GetDbInstance(
LPCWSTR wszDbKey,
IWbemClassObject** ppInstance
)
{
// ESS uses this one
return CRepository::GetObject(m_pSession, m_pScopeHandle, wszDbKey, 0, ppInstance);
}
//***************************************************************************
//
//***************************************************************************
STDMETHODIMP CWbemNamespace::GetDbReferences(
IWbemClassObject* pEndpoint,
IWbemObjectSink* pSink)
{
LPWSTR wszRelPath = ((CWbemObject*)pEndpoint)->GetRelPath();
CVectorDeleteMe<WCHAR> dm(wszRelPath);
CSimpleWrapperSink ws(pSink);
HRESULT hRes = CRepository::GetInstanceRefs(m_pSession,m_pScopeHandle, wszRelPath, &ws);
return hRes;
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWbemNamespace::InternalPutStaticClass(
IWbemClassObject* pClass)
{
if (g_bDontAllowNewConnections || m_bShutDown)
{
return WBEM_E_SHUTTING_DOWN;
}
IWbemContext *pContext = NULL ;
CWbemRequest* pReq = CWbemQueue::GetCurrentRequest() ;
if (pReq == NULL)
{
pContext = ConfigMgr::GetNewContext();
if ( pContext == NULL )
return WBEM_E_OUT_OF_MEMORY;
}
else
{
pContext = pReq->GetContext();
pContext->AddRef () ; //for CReleaseMe
}
CReleaseMe _1_pContext (pContext) ;
CSynchronousSink* pSink = CSynchronousSink::Create();
if(pSink == NULL)
return WBEM_E_OUT_OF_MEMORY;
pSink->AddRef();
CReleaseMe rm1(pSink);
Exec_PutClass( pClass, 0, pContext, pSink, TRUE );
HRESULT hres = WBEM_E_CRITICAL_ERROR;
pSink->GetStatus(&hres, NULL, NULL);
return hres;
}
//***************************************************************************
//
// CWbemNamespace::AdjustPutContext
//
//***************************************************************************
HRESULT CWbemNamespace::AdjustPutContext(
IWbemContext *pCtx
)
{
// See if per-property puts are being used.
// ========================================
HRESULT hRes;
if (pCtx == 0)
return WBEM_S_NO_ERROR;
CVARIANT v;
hRes = pCtx->GetValue(L"__PUT_EXTENSIONS", 0, &v);
if (SUCCEEDED(hRes))
{
// If here, they are being used. Next we have to check and see
// if the reentrancy flag is set or not.
// =============================================================
hRes = pCtx->GetValue(L"__PUT_EXT_CLIENT_REQUEST", 0, &v);
if (SUCCEEDED(hRes))
{
pCtx->DeleteValue(L"__PUT_EXT_CLIENT_REQUEST", 0);
return WBEM_S_NO_ERROR;
}
// If here, we have to clear out the put extensions.
// =================================================
pCtx->DeleteValue(L"__PUT_EXTENSIONS", 0);
pCtx->DeleteValue(L"__PUT_EXT_CLIENT_REQUEST", 0);
pCtx->DeleteValue(L"__PUT_EXT_ATOMIC", 0);
pCtx->DeleteValue(L"__PUT_EXT_PROPERTIES", 0);
pCtx->DeleteValue(L"__PUT_EXT_STRICT_NULLS", 0);
}
return WBEM_S_NO_ERROR;
}
//***************************************************************************
//
// CWbemNamespace::MergeGetKeysCtx
//
//***************************************************************************
//
HRESULT CWbemNamespace::MergeGetKeysCtx(
IN IWbemContext *pCtx
)
{
HRESULT hRes;
if (pCtx == 0)
return WBEM_S_NO_ERROR;
CVARIANT v;
v.SetBool(TRUE);
hRes = pCtx->SetValue(L"__GET_EXTENSIONS", 0, &v);
hRes |= pCtx->SetValue(L"__GET_EXT_KEYS_ONLY", 0, &v);
hRes |= pCtx->SetValue(L"__GET_EXT_CLIENT_REQUEST", 0, &v);
return hRes;
}
//***************************************************************************
//
// CWbemNamespace::CheckNs
//
// Does a quick check on the available system resources before allowing
// a new call to proceed. Retries for 30 seconds.
//
//***************************************************************************
//
HRESULT CWbemNamespace::CheckNs()
{
HRESULT hr = WBEM_S_NO_ERROR;
if (g_bDontAllowNewConnections || m_bShutDown)
{
return WBEM_E_SHUTTING_DOWN;
}
// Quick memory check. If we are strapped for RAM/Pagefile,
// wait a while and try again. Requirements are 1 meg of
// available RAM and 1 meg of available page file.
int nRetries = 0;
for (int i = 0; i < 30; i++)
{
MEMORYSTATUS ms;
GlobalMemoryStatus(&ms);
if (ms.dwMemoryLoad < 99)
return WBEM_S_NO_ERROR;
// If here, we have to be careful. The system is loaded at 99%.
// =============================================================
if (nRetries > 30)
{
// Sixty seconds waiting for enough memory. Give up.
return WBEM_E_OUT_OF_MEMORY;
}
DWORD dwPracticalMemory = ms.dwAvailPhys + ms.dwAvailPageFile;
if (dwPracticalMemory < 0x200000) // 2 meg
{
Sleep(2000);
// Try a 1 meg allocation to see if will succeed.
LPVOID pTestMem = HeapAlloc(GetProcessHeap(), 0, 0x100000);
if (pTestMem == 0)
{
return WBEM_E_OUT_OF_MEMORY;
}
// Free the memory. The previous allocation may have
// grown the pagefile and thus we can succeed.
HeapFree(GetProcessHeap(), 0, pTestMem);
nRetries++;
}
else
{
// If here, we have a load of 99%, yet more than 2 meg of memory
// still available. Now 99% may mean there is a lot of free memory
// because the machine has huge resources or it may mean we are just
// about out of memory completely. We need hard data. If we
// have at least 5 meg anyway, this is clearly adequate, so we just
// break out of the loop and let the call continue.
//
// Otherwise, we have between 2 and 5 meg, which is starting to push
// it. We enter a waiting loop and hope for more memory. After a few
// retries if we continue to have between 2 and 5 meg, we'll let the call
// through and let the arbitrator deal with it, since the system appears
// to have stabilized at this usage.
//
hr = WBEM_S_NO_ERROR;
if (ms.dwAvailPhys < 0x200000) // If low on physical memory back off a bit for recovery via pagefile
Sleep(1000);
if (dwPracticalMemory > 0x100000 * 5) // > 5 meg; break out immediately
break;
// Under 5 meg free, retry a few times to let things clear up and get
// more memory. But, we succeed in the end anyway.
// ==================================================================
Sleep(1000);
if (nRetries++ > 5)
{
hr = WBEM_S_NO_ERROR;
break;
}
}
}
return hr;
}
//***************************************************************************
//
//***************************************************************************
//
HRESULT CWbemNamespace::UniversalConnect(
CWbemNamespace *pParent,
IWbemContext *pCtx,
LPCWSTR pszNewScope,
LPCWSTR pszAssocSelector,
LPCWSTR pszUserName,
_IWmiCallSec *pCallSec,
_IWmiUserHandle *pUser,
DWORD dwUserFlags,
DWORD dwInternalFlags,
DWORD dwSecFlags,
DWORD dwPermission,
BOOL bForClient,
BOOL bRepositOnly,
LPCWSTR pszClientMachineName,
DWORD dwClientProcessID,
IN REFIID riid,
OUT LPVOID *pConnection
)
{
HRESULT hRes;
if(dwUserFlags & WBEM_FLAG_CONNECT_REPOSITORY_ONLY)
bRepositOnly = TRUE;
// Validate.
if (pszNewScope == 0)
return WBEM_E_INVALID_PARAMETER;
if (riid != IID_IWbemServices )
return E_NOINTERFACE;
// If no parent, then this is an 'absolute' connect.
// =================================================
if (!pParent)
{
CWbemNamespace *pNs = CWbemNamespace::CreateInstance();
if (NULL == pNs) return WBEM_E_OUT_OF_MEMORY;
hRes = pNs->Initialize(
LPWSTR(pszNewScope),
LPWSTR(pszUserName),
dwSecFlags,
dwPermission,
bForClient,
bRepositOnly,
pszClientMachineName,
dwClientProcessID,
FALSE,
NULL);
if (FAILED(hRes))
{
pNs->Release();
return hRes;
}
pNs->SetIsProvider((dwUserFlags & WBEM_FLAG_CONNECT_PROVIDERS)?TRUE:FALSE);
*pConnection = pNs;
return WBEM_S_NO_ERROR;
}
else
{
return WBEM_E_INVALID_OPERATION;
}
}
//***************************************************************************
//
// Called by _IWmiCoreServices to establish a connection from the 'outside'.
//
//***************************************************************************
//
HRESULT CWbemNamespace::PathBasedConnect(
/* [in] */ LPCWSTR pszPath,
/* [in] */ LPCWSTR pszUser,
/* [in] */ IWbemContext __RPC_FAR *pCtx,
/* [in] */ ULONG uClientFlags,
/* [in] */ DWORD dwSecFlags,
/* [in] */ DWORD dwPermissions,
/* [in] */ ULONG uInternalFlags,
/* [in] */ LPCWSTR pszClientMachineName,
/* [in] */ DWORD dwClientProcessID,
/* [in] */ REFIID riid,
/* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *pServices
)
{
HRESULT hRes;
BOOL bForClient = FALSE;
if ((uInternalFlags & WMICORE_CLIENT_ORIGIN_LOCAL) ||
(uInternalFlags & WMICORE_CLIENT_ORIGIN_REMOTE) ||
(uInternalFlags & WMICORE_CLIENT_TYPE_ALT_TRANSPORT)
)
{
bForClient = TRUE;
}
hRes = UniversalConnect(
0, // Parent CWbemNamespace; not known
pCtx, // Context
pszPath, // Path
0, // No assoc selector at this point
pszUser, // User
0, // Call security
0, // User handle
uClientFlags, // Flags from client
uInternalFlags, // Internal flags
dwSecFlags, // Copy
dwPermissions, // Copy
bForClient, // For client?
FALSE, // Repository only
pszClientMachineName,
dwClientProcessID,
riid,
pServices
);
return hRes;
}
//***************************************************************************
//
//***************************************************************************
//
HRESULT CWbemNamespace::InitNewTask(
IN CAsyncReq *pReq,
IN _IWmiFinalizer *pFnz,
IN ULONG uTaskType,
IN IWbemContext *pCtx,
IN IWbemObjectSink *pAsyncClientSink
)
{
HRESULT hRes;
if (pReq == 0 || pFnz == 0)
return WBEM_E_INVALID_PARAMETER;
// Create a task for tracking the operation.
// =========================================
CWmiTask *pNewTask = CWmiTask::CreateTask();
if (pNewTask == 0)
return WBEM_E_OUT_OF_MEMORY;
CReleaseMe _2(pNewTask);
hRes = pNewTask->Initialize(this, uTaskType, pCtx, pAsyncClientSink,pReq);
if (FAILED(hRes))
return hRes;
hRes = pFnz->SetTaskHandle((_IWmiCoreHandle *) pNewTask);
if (FAILED(hRes))
return hRes;
pReq->SetTaskHandle((_IWmiCoreHandle *) pNewTask);
return WBEM_S_NO_ERROR;
}
//***************************************************************************
//
//***************************************************************************
//
HRESULT CWbemNamespace::CreateSyncFinalizer(
IN IWbemContext *pCtx,
IN _IWmiFinalizer **pResultFnz
)
{
HRESULT hRes;
ULONG uFlags = WMI_FNLZR_FLAG_FAST_TRACK;
// Determine calling context to see if the call is reentrant or what.
// ==================================================================
IWbemCausalityAccess *pCaus = 0;
if (pCtx != 0)
{
hRes = pCtx->QueryInterface(IID_IWbemCausalityAccess, (LPVOID *) &pCaus);
if (SUCCEEDED(hRes))
{
long lNumParents = 0;
long lNumSiblings = 0;
pCaus->GetHistoryInfo(&lNumParents, &lNumSiblings);
if (lNumParents)
uFlags = WMI_FNLZR_FLAG_FAST_TRACK;
pCaus->Release();
}
}
// Create Finalizer.
// =================
_IWmiFinalizer *pFnz = 0;
hRes = m_pCoreSvc->CreateFinalizer(0, &pFnz);
if (FAILED(hRes))
return hRes;
CReleaseMe _(pFnz);
hRes = pFnz->Configure(uFlags, 0);
if (FAILED(hRes))
return hRes;
pFnz->AddRef();
*pResultFnz = pFnz;
return WBEM_S_NO_ERROR;
}
//***************************************************************************
//
//***************************************************************************
//
HRESULT CWbemNamespace::CreateAsyncFinalizer(
IWbemContext *pCtx,
IWbemObjectSink *pStartingSink,
_IWmiFinalizer **pResultFnz,
IWbemObjectSink **pResultSinkEx
)
{
HRESULT hRes;
ULONG uFlags = WMI_FNLZR_FLAG_FAST_TRACK;
if ( m_bForClient )
uFlags = WMI_FNLZR_FLAG_DECOUPLED;
// Determine calling context to see if the call is reentrant or what.
// ==================================================================
IWbemCausalityAccess *pCaus = 0;
if (pCtx != 0)
{
hRes = pCtx->QueryInterface(IID_IWbemCausalityAccess, (LPVOID *) &pCaus);
if (SUCCEEDED(hRes))
{
long lNumParents = 0;
long lNumSiblings = 0;
pCaus->GetHistoryInfo(&lNumParents, &lNumSiblings);
if (lNumParents)
uFlags = WMI_FNLZR_FLAG_FAST_TRACK;
pCaus->Release();
}
}
// Create Finalizer.
// =================
_IWmiFinalizer *pFnz = 0;
hRes = m_pCoreSvc->CreateFinalizer(0, &pFnz);
if (FAILED(hRes))
return hRes;
CReleaseMe _(pFnz);
hRes = pFnz->Configure(uFlags, 0);
if (FAILED(hRes))
return hRes;
hRes = pFnz->SetDestinationSink(0, IID_IWbemObjectSink, (LPVOID) pStartingSink);
if (FAILED(hRes))
return hRes;
hRes = pFnz->NewInboundSink(0, pResultSinkEx);
if (FAILED(hRes))
return hRes;
pFnz->AddRef();
*pResultFnz = pFnz;
return WBEM_S_NO_ERROR;
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//
// Native async operations
//
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//
// InstEnum Sync[ ] Async Impl[x] AsyncEntry[x]
// ClassEnum Sync[ ] Async Impl[x] AsyncEntry[x]
//
// PutInst Sync[ ] Async Impl[x] AsyncEntry[x]
// PutClass Sync[ ] Async Impl[x] AsyncEntry[x]
// DelInst Sync[ ] Async Impl[x] AsyncEntry[x]
// DelClass Sync[ ] Async Impl[x] AsyncEntry[x]
//
// GetObject Sync[ ] Async Impl[x] AsyncEntry[x]
//
// ExecQuery Sync[ ] Async Impl[x] AsyncEntry[x]
// ExecMethod Sync[ ] Async Impl[x] AsyncEntry[x]
//
//
//***************************************************************************
//
//***************************************************************************
// ok
HRESULT CWbemNamespace::DeleteClassAsync(
const BSTR strClass,
long lFlags,
IWbemContext* pCtx,
IWbemObjectSink* pHandler
)
{
try
{
return _DeleteClassAsync(
WMICORE_TASK_TYPE_ASYNC | WMICORE_TASK_DELETE_CLASS,
0, 0, strClass, lFlags, pCtx, pHandler
);
}
catch (...)
{
ExceptionCounter c;
return WBEM_E_CRITICAL_ERROR;
}
}
//***************************************************************************
//
//***************************************************************************
// ok
HRESULT CWbemNamespace::CreateClassEnumAsync(
const BSTR strParent,
long lFlags,
IWbemContext* pCtx,
IWbemObjectSink* pHandler
)
{
try
{
return _CreateClassEnumAsync(
WMICORE_TASK_TYPE_ASYNC | WMICORE_TASK_ENUM_CLASSES,
0, 0, strParent, lFlags, pCtx, pHandler
);
}
catch (...)
{
ExceptionCounter c;
return WBEM_E_CRITICAL_ERROR;
}
}
//***************************************************************************
//
//***************************************************************************
// ok
HRESULT CWbemNamespace::PutClassAsync(
READONLY IWbemClassObject* pObj,
long lFlags,
IWbemContext* pCtx,
IWbemObjectSink* pHandler
)
{
try
{
return _PutClassAsync(
WMICORE_TASK_TYPE_ASYNC | WMICORE_TASK_PUT_CLASS,
0, 0, pObj, lFlags, pCtx, pHandler
);
}
catch (...)
{
ExceptionCounter c;
return WBEM_E_CRITICAL_ERROR;
}
}
//***************************************************************************
//
//***************************************************************************
// ok
HRESULT CWbemNamespace::PutInstanceAsync(
IWbemClassObject* pInst,
long lFlags,
IWbemContext* pCtx,
IWbemObjectSink* pHandler
)
{
try
{
return _PutInstanceAsync(WMICORE_TASK_TYPE_ASYNC| WMICORE_TASK_PUT_INSTANCE,
0, 0, pInst, lFlags, pCtx, pHandler);
}
catch (...)
{
ExceptionCounter c;
return WBEM_E_CRITICAL_ERROR;
}
}
//***************************************************************************
//
//***************************************************************************
// ok
HRESULT CWbemNamespace::DeleteInstanceAsync(
const BSTR strObjectPath,
long lFlags,
IWbemContext* pCtx,
IWbemObjectSink* pHandler
)
{
try
{
return _DeleteInstanceAsync(
WMICORE_TASK_TYPE_ASYNC| WMICORE_TASK_DELETE_INSTANCE,
0, 0, strObjectPath, lFlags, pCtx, pHandler
);
}
catch (...)
{
ExceptionCounter c;
return WBEM_E_CRITICAL_ERROR;
}
}
//***************************************************************************
//
//***************************************************************************
// ok
HRESULT CWbemNamespace::CreateInstanceEnumAsync(
const BSTR strClass,
long lFlags,
IWbemContext* pCtx,
IWbemObjectSink* pHandler
)
{
try
{
return _CreateInstanceEnumAsync(
WMICORE_TASK_TYPE_ASYNC | WMICORE_TASK_ENUM_INSTANCES,
0, 0,
strClass, lFlags, pCtx, pHandler
);
}
catch (...)
{
ExceptionCounter c;
return WBEM_E_CRITICAL_ERROR;
}
}
//***************************************************************************
//
//***************************************************************************
// ok
HRESULT CWbemNamespace::ExecQueryAsync(
const BSTR strQueryFormat,
const BSTR strQuery,
long lFlags,
IWbemContext* pCtx,
IWbemObjectSink* pHandler
)
{
try
{
return _ExecQueryAsync(WMICORE_TASK_TYPE_ASYNC | WMICORE_TASK_EXEC_QUERY,
0, 0,
strQueryFormat, strQuery, lFlags, pCtx, pHandler);
}
catch(...)
{
ExceptionCounter c;
return WBEM_E_CRITICAL_ERROR;
}
}
//***************************************************************************
//
//***************************************************************************
// ok
HRESULT CWbemNamespace::ExecMethodAsync(
const BSTR ObjectPath,
const BSTR MethodName,
long lFlags,
IWbemContext *pCtx,
IWbemClassObject *pInParams,
IWbemObjectSink* pHandler
)
{
try
{
return _ExecMethodAsync(WMICORE_TASK_TYPE_ASYNC | WMICORE_TASK_EXEC_METHOD,
0, 0,
ObjectPath,
MethodName,
lFlags,
pCtx,
pInParams,
pHandler);
}
catch (...)
{
ExceptionCounter c;
return WBEM_E_CRITICAL_ERROR;
}
}
//***************************************************************************
//
//***************************************************************************
//
HRESULT CWbemNamespace::GetObjectAsync(
const BSTR strObjectPath,
long lFlags,
IWbemContext* pCtx,
IWbemObjectSink* pHandler
)
{
HRESULT hRes = CheckNs();
if (FAILED(hRes))
return hRes;
if (!Allowed(WBEM_ENABLE))
return WBEM_E_ACCESS_DENIED;
try
{
return _GetObjectAsync(
WMICORE_TASK_TYPE_ASYNC | WMICORE_TASK_GET_OBJECT,
0, 0,
strObjectPath,
lFlags,
pCtx,
pHandler
);
}
catch (...)
{
ExceptionCounter c;
return WBEM_E_CRITICAL_ERROR;
}
}
//
// can throw
//
///////////////////////////////////////////////////////////////////////
HRESULT CWbemNamespace::_PutInstanceAsync(
IN ULONG uInternalFlags,
IN _IWmiFinalizer *pFnz,
IN _IWmiCoreHandle *phTask,
IWbemClassObject* pInst,
long lFlags,
IWbemContext* pCtx,
IWbemObjectSink* pHandler
)
{
HRESULT hRes = CheckNs();
if (FAILED(hRes))
return hRes;
DEBUGTRACE((LOG_WBEMCORE,
"CALL CWbemNamespace::PutInstanceAsync"
" long lFlags = 0x%X\n"
" IWbemClassObject *pInst = 0x%X\n"
" IWbemObjectSink* pHandler = 0x%X\n",
lFlags,
pInst,
pHandler
));
// Parameter and object validation.
// ================================
if (pFnz == 0 && pHandler == 0)
return WBEM_E_INVALID_PARAMETER;
if (pInst == NULL)
return WBEM_E_INVALID_PARAMETER;
long lMainFlags = lFlags & ~WBEM_FLAG_SEND_STATUS & ~WBEM_FLAG_USE_AMENDED_QUALIFIERS & ~WBEM_FLAG_OWNER_UPDATE;
if (lMainFlags != WBEM_FLAG_CREATE_ONLY &&
lMainFlags != WBEM_FLAG_UPDATE_ONLY &&
lMainFlags != WBEM_FLAG_CREATE_OR_UPDATE)
{
return WBEM_E_INVALID_PARAMETER;
}
if (!m_bProvider && (lFlags & WBEM_FLAG_OWNER_UPDATE))
{
return WBEM_E_INVALID_PARAMETER;
}
if (lFlags & WBEM_FLAG_OWNER_UPDATE)
{
lFlags -= WBEM_FLAG_OWNER_UPDATE;
lFlags += WBEM_FLAG_NO_EVENTS;
}
// Check for per-property put context info.
// ========================================
if (pCtx) AdjustPutContext(pCtx);
// Create Finalizer.
// =================
IWbemObjectSink *pPseudoSink = 0;
if (pFnz == 0)
{
hRes = CreateAsyncFinalizer(pCtx, pHandler, &pFnz, &pPseudoSink);
if (FAILED(hRes))
return hRes;
}
else // borrowed finalizer
{
hRes = pFnz->NewInboundSink(0, &pPseudoSink);
if (FAILED(hRes))
return hRes;
pFnz->AddRef();
}
CReleaseMe _1(pPseudoSink);
CReleaseMe _2(pFnz);
// Schedule the request.
// =====================
wmilib::auto_ptr<CAsyncReq_PutInstanceAsync> pReq;
pReq.reset(new CAsyncReq_PutInstanceAsync( this, pInst, lFlags, pPseudoSink, pCtx));
if (NULL == pReq.get()) return WBEM_E_OUT_OF_MEMORY;
if (NULL == pReq->GetContext()) return WBEM_E_OUT_OF_MEMORY;
hRes = InitNewTask(pReq.get(), pFnz, uInternalFlags, pReq->GetContext(), pHandler);
if (FAILED(hRes)) return hRes;
_1.release();
hRes = ConfigMgr::EnqueueRequest(pReq.get());
if (FAILED(hRes))
{
pFnz->CancelTask ( 0 );
return hRes;
}
pReq.release();
return hRes;
}
//
// can throw
//
//////////////////////////////////////////////////////
HRESULT CWbemNamespace::_DeleteClassAsync(
IN ULONG uInternalFlags,
IN _IWmiFinalizer *pFnz,
IN _IWmiCoreHandle *phTask,
const BSTR strClassOrg,
long lFlags,
IWbemContext* pCtx,
IWbemObjectSink* pHandler
)
{
HRESULT hRes = CheckNs();
if (FAILED(hRes))
return hRes;
// Parameter validation.
// =====================
if (pFnz == 0 && pHandler == 0)
return WBEM_E_INVALID_PARAMETER;
if (strClassOrg == 0 || strClassOrg[0] == 0)
return WBEM_E_INVALID_PARAMETER;
if (wcslen_max(strClassOrg,g_IdentifierLimit) > g_IdentifierLimit) return WBEM_E_QUOTA_VIOLATION;
WCHAR * strClass;
if (L'\\' == strClassOrg[0] || L'/' == strClassOrg[0] )
{
strClass = wcschr(strClassOrg, L':');
if (NULL == strClass) return WBEM_E_INVALID_OBJECT_PATH;
strClass++;
if (0 == strClass[0]) return WBEM_E_INVALID_PARAMETER;
}
else
{
strClass = strClassOrg;
}
if (!m_bProvider && (lFlags & WBEM_FLAG_OWNER_UPDATE))
return WBEM_E_INVALID_PARAMETER;
if (lFlags & ~WBEM_FLAG_SEND_STATUS & ~WBEM_FLAG_OWNER_UPDATE)
return WBEM_E_INVALID_PARAMETER;
if (lFlags & WBEM_FLAG_OWNER_UPDATE)
{
lFlags -= WBEM_FLAG_OWNER_UPDATE;
lFlags += WBEM_FLAG_NO_EVENTS;
}
// Create Finalizer.
// =================
IWbemObjectSink *pPseudoSink = 0;
if (pFnz == 0)
{
hRes = CreateAsyncFinalizer(pCtx, pHandler, &pFnz, &pPseudoSink);
if (FAILED(hRes))
return hRes;
}
else // borrowed finalizer
{
hRes = pFnz->NewInboundSink(0, &pPseudoSink);
if (FAILED(hRes))
return hRes;
pFnz->AddRef();
}
CReleaseMe _1(pPseudoSink);
CReleaseMe _2(pFnz);
// Create request.
// ===============
wmilib::auto_ptr<CAsyncReq_DeleteClassAsync> pReq;
pReq.reset(new CAsyncReq_DeleteClassAsync( this, strClass, lFlags, pPseudoSink, pCtx));
if (pReq.get() == NULL) return WBEM_E_OUT_OF_MEMORY;
if (NULL == pReq->GetContext()) return WBEM_E_OUT_OF_MEMORY;
hRes = InitNewTask(pReq.get(), pFnz, uInternalFlags, pReq->GetContext(), pHandler);
if (FAILED(hRes)) return hRes;
_1.release();
hRes = ConfigMgr::EnqueueRequest(pReq.get());
if (FAILED(hRes))
{
pFnz->CancelTask ( 0 );
return hRes;
}
pReq.release();
return hRes;
}
//***************************************************************************
//
//***************************************************************************
//
HRESULT CWbemNamespace::_CreateClassEnumAsync(
IN ULONG uInternalFlags,
IN _IWmiFinalizer *pFnz,
IN _IWmiCoreHandle *phTask,
const BSTR strParent,
long lFlags,
IWbemContext* pCtx,
IWbemObjectSink* pHandler
)
{
HRESULT hRes = CheckNs();
if (FAILED(hRes))
return hRes;
if (!Allowed(WBEM_ENABLE))
return WBEM_E_ACCESS_DENIED;
DEBUGTRACE((LOG_WBEMCORE,
"CALL CWbemNamespace::CreateClassEnumAsync\n"
" BSTR strParent = %S\n"
" long lFlags = 0x%X\n"
" IWbemObjectSink* pHandler = 0x%X\n",
strParent,
lFlags,
pHandler
));
// Parameter validation.
// =====================
if (pFnz == 0 && pHandler == 0)
return WBEM_E_INVALID_PARAMETER;
if (strParent)
{
if (wcslen_max(strParent,g_IdentifierLimit) > g_IdentifierLimit)
return WBEM_E_QUOTA_VIOLATION;
}
if (lFlags & ~(WBEM_FLAG_DEEP | WBEM_FLAG_SHALLOW | WBEM_FLAG_SEND_STATUS) & ~WBEM_FLAG_USE_AMENDED_QUALIFIERS)
return WBEM_E_INVALID_PARAMETER;
// Create Finalizer.
// =================
IWbemObjectSink *pPseudoSink = 0;
if (pFnz == 0)
{
hRes = CreateAsyncFinalizer(pCtx, pHandler, &pFnz, &pPseudoSink);
if (FAILED(hRes))
return hRes;
}
else // borrowed finalizer
{
hRes = pFnz->NewInboundSink(0, &pPseudoSink);
if (FAILED(hRes))
return hRes;
pFnz->AddRef();
}
CReleaseMe _1(pPseudoSink);
CReleaseMe _2(pFnz);
// Add this request to the queue.
// ==============================
wmilib::auto_ptr<CAsyncReq_CreateClassEnumAsync> pReq;
pReq.reset(new CAsyncReq_CreateClassEnumAsync(this, strParent, lFlags, pPseudoSink,pCtx));
if (NULL == pReq.get()) return WBEM_E_OUT_OF_MEMORY;
if (NULL == pReq->GetContext()) return WBEM_E_OUT_OF_MEMORY;
hRes = InitNewTask(pReq.get(), pFnz, uInternalFlags, pReq->GetContext(), pHandler);
if (FAILED(hRes)) return hRes;
_1.release();
hRes = ConfigMgr::EnqueueRequest(pReq.get());
if (FAILED(hRes))
{
pFnz->CancelTask ( 0 );
return hRes;
}
pReq.release();
return hRes;
}
//***************************************************************************
//
//***************************************************************************
//
HRESULT CWbemNamespace::_PutClassAsync(
IN ULONG uInternalFlags,
IN _IWmiFinalizer *pFnz,
IN _IWmiCoreHandle *phTask,
READONLY IWbemClassObject* pObj,
long lFlags,
IWbemContext* pCtx,
IWbemObjectSink* pHandler
)
{
HRESULT hRes = CheckNs();
if (FAILED(hRes))
return hRes;
CVARIANT vClass;
if (pObj)
{
hRes = pObj->Get(L"__CLASS", 0, &vClass, 0, 0);
}
DEBUGTRACE((LOG_WBEMCORE,
"CALL CWbemNamespace::PutClassAsync\n"
" long lFlags = 0x%X\n"
" IWbemClassObject *pObj = 0x%X\n"
" IWbemObjectSink* pNotify = 0x%X\n"
" __CLASS=%S\n",
lFlags,
pObj,
pHandler,
vClass.GetStr()
));
if (pFnz == 0 && pHandler == 0)
return WBEM_E_INVALID_PARAMETER;
if (pObj == NULL)
return WBEM_E_INVALID_PARAMETER;
if(!m_bProvider && (lFlags & WBEM_FLAG_OWNER_UPDATE))
{
return WBEM_E_INVALID_PARAMETER;
}
long lTestFlags = lFlags & ~WBEM_FLAG_SEND_STATUS & ~WBEM_FLAG_OWNER_UPDATE
& ~WBEM_MASK_UPDATE_MODE & ~WBEM_FLAG_USE_AMENDED_QUALIFIERS;
if (!((lTestFlags == WBEM_FLAG_CREATE_OR_UPDATE) ||
(lTestFlags == WBEM_FLAG_UPDATE_ONLY) ||
(lTestFlags == WBEM_FLAG_CREATE_ONLY) ||
(lTestFlags == WBEM_FLAG_UPDATE_SAFE_MODE) ||
(lTestFlags == WBEM_FLAG_UPDATE_FORCE_MODE) ||
(lTestFlags == (WBEM_FLAG_UPDATE_ONLY | WBEM_FLAG_UPDATE_SAFE_MODE)) ||
(lTestFlags == (WBEM_FLAG_UPDATE_ONLY | WBEM_FLAG_UPDATE_FORCE_MODE))))
{
return WBEM_E_INVALID_PARAMETER;
}
if (lFlags & WBEM_FLAG_OWNER_UPDATE)
{
lFlags -= WBEM_FLAG_OWNER_UPDATE;
lFlags += WBEM_FLAG_NO_EVENTS;
}
// Create Finalizer.
// =================
IWbemObjectSink *pPseudoSink = 0;
if (pFnz == 0)
{
hRes = CreateAsyncFinalizer(pCtx, pHandler, &pFnz, &pPseudoSink);
if (FAILED(hRes))
return hRes;
}
else // borrowed finalizer
{
hRes = pFnz->NewInboundSink(0, &pPseudoSink);
if (FAILED(hRes))
return hRes;
pFnz->AddRef();
}
CReleaseMe _1(pPseudoSink);
CReleaseMe _2(pFnz);
// Create request.
// ===============
wmilib::auto_ptr<CAsyncReq_PutClassAsync> pReq;
pReq.reset(new CAsyncReq_PutClassAsync(this, pObj, lFlags, pPseudoSink, pCtx));
if (NULL == pReq.get()) return WBEM_E_OUT_OF_MEMORY;
if (NULL == pReq->GetContext()) return WBEM_E_OUT_OF_MEMORY;
hRes = InitNewTask(pReq.get(), pFnz, uInternalFlags, pReq->GetContext(), pHandler);
if (FAILED(hRes)) return hRes;
_1.release();
hRes = ConfigMgr::EnqueueRequest(pReq.get());
if (FAILED(hRes))
{
pFnz->CancelTask ( 0 );
return hRes;
}
pReq.release();
return hRes;
}
//***************************************************************************
//
//***************************************************************************
//
HRESULT CWbemNamespace::_DeleteInstanceAsync(
IN ULONG uInternalFlags,
IN _IWmiFinalizer *pFnz,
IN _IWmiCoreHandle *phTask,
READONLY const BSTR strObjectPath,
long lFlags,
IWbemContext* pCtx,
IWbemObjectSink* pHandler
)
{
HRESULT hRes = CheckNs();
if (FAILED(hRes))
return hRes;
DEBUGTRACE((LOG_WBEMCORE,
"CALL CWbemNamespace::DeleteInstance\n"
" BSTR ObjectPath = %S\n"
" long lFlags = %d\n"
" IWbemObjectSink* pHandler = 0x%X\n",
strObjectPath, lFlags, pHandler
));
// Parameter validation.
// =====================
if (pFnz == 0 && pHandler == 0)
return WBEM_E_INVALID_PARAMETER;
if (strObjectPath == 0 || strObjectPath[0] == 0)
return WBEM_E_INVALID_PARAMETER;
if (wcslen_max(strObjectPath,g_PathLimit) > g_PathLimit)
return WBEM_E_QUOTA_VIOLATION;
if (!m_bProvider && (lFlags & WBEM_FLAG_OWNER_UPDATE))
{
return WBEM_E_INVALID_PARAMETER;
}
if (lFlags & ~WBEM_FLAG_SEND_STATUS & ~WBEM_FLAG_OWNER_UPDATE)
return WBEM_E_INVALID_PARAMETER;
if (lFlags & WBEM_FLAG_OWNER_UPDATE)
{
lFlags -= WBEM_FLAG_OWNER_UPDATE;
lFlags += WBEM_FLAG_NO_EVENTS;
}
// Create Finalizer.
// =================
IWbemObjectSink *pPseudoSink = 0;
if (pFnz == 0)
{
hRes = CreateAsyncFinalizer(pCtx, pHandler, &pFnz, &pPseudoSink);
if (FAILED(hRes))
return hRes;
}
else // borrowed finalizer
{
hRes = pFnz->NewInboundSink(0, &pPseudoSink);
if (FAILED(hRes))
return hRes;
pFnz->AddRef();
}
CReleaseMe _1(pPseudoSink);
CReleaseMe _2(pFnz);
// Create request.
// ===============
wmilib::auto_ptr<CAsyncReq_DeleteInstanceAsync> pReq;
pReq.reset(new CAsyncReq_DeleteInstanceAsync(this, strObjectPath, lFlags, pPseudoSink, pCtx));
if (NULL == pReq.get())return WBEM_E_OUT_OF_MEMORY;
if ( NULL == pReq->GetContext()) return WBEM_E_OUT_OF_MEMORY;
hRes = InitNewTask(pReq.get(), pFnz, uInternalFlags, pReq->GetContext(), pHandler);
if (FAILED(hRes)) return hRes;
_1.release();
hRes = ConfigMgr::EnqueueRequest(pReq.get());
if (FAILED(hRes))
{
pFnz->CancelTask ( 0 );
return hRes;
}
pReq.release();
return hRes;
}
//***************************************************************************
//
// CWbemNamespace::CreateInstanceEnumAsync
//
// Schedules an asynchrnous request that eventuall calls
// Exec_CreateInstanceEnum.
//
// Parameters and return values are described in help
//
//***************************************************************************
//
HRESULT CWbemNamespace::_CreateInstanceEnumAsync(
IN ULONG uInternalFlags,
IN _IWmiFinalizer *pFnz,
IN _IWmiCoreHandle *phTask,
const BSTR strClass,
long lFlags,
IWbemContext* pCtx,
IWbemObjectSink* pHandler
)
{
HRESULT hRes = CheckNs();
if (FAILED(hRes))
return hRes;
if (!Allowed(WBEM_ENABLE))
return WBEM_E_ACCESS_DENIED;
DEBUGTRACE((LOG_WBEMCORE,
"CALL CWbemNamespace::CreateInstanceEnumAsync\n"
" BSTR Class = %S\n"
" long lFlags = 0x%X\n"
" IWbemObjectSink pHandler = 0x%X\n",
strClass,
lFlags,
pHandler
));
// Parameter validation.
// =====================
if (pFnz == 0 && pHandler == 0)
return WBEM_E_INVALID_PARAMETER;
if (strClass == 0 || strClass[0] == 0)
return WBEM_E_INVALID_PARAMETER;
if (wcslen_max(strClass,g_IdentifierLimit) > g_IdentifierLimit)
return WBEM_E_QUOTA_VIOLATION;
if (lFlags & ~(WBEM_FLAG_DEEP | WBEM_FLAG_SHALLOW | WBEM_FLAG_SEND_STATUS |
WBEM_FLAG_USE_AMENDED_QUALIFIERS | WBEM_FLAG_DIRECT_READ))
return WBEM_E_INVALID_PARAMETER;
// Create Finalizer.
// =================
IWbemObjectSink *pPseudoSink = 0;
if (pFnz == 0)
{
hRes = CreateAsyncFinalizer(pCtx, pHandler, &pFnz, &pPseudoSink);
if (FAILED(hRes))
return hRes;
}
else // borrowed finalizer
{
hRes = pFnz->NewInboundSink(0, &pPseudoSink);
if (FAILED(hRes))
return hRes;
pFnz->AddRef();
}
CReleaseMe _1(pPseudoSink);
CReleaseMe _2(pFnz);
// Add this request to the async queue.
// ====================================
wmilib::auto_ptr<CAsyncReq_CreateInstanceEnumAsync> pReq;
pReq.reset(new CAsyncReq_CreateInstanceEnumAsync(this, strClass, lFlags, pPseudoSink,pCtx));
if (NULL == pReq.get()) return WBEM_E_OUT_OF_MEMORY;
if (NULL == pReq->GetContext()) return WBEM_E_OUT_OF_MEMORY;
hRes = InitNewTask(pReq.get(), pFnz, uInternalFlags, pReq->GetContext(), pHandler);
if (FAILED(hRes)) return hRes;
_1.release();
hRes = ConfigMgr::EnqueueRequest(pReq.get());
if (FAILED(hRes))
{
pFnz->CancelTask ( 0 );
return hRes;
}
pReq.release();
return hRes;
}
//***************************************************************************
//
// CWbemNamespace::ExecQueryAsync
//
// Schedules an asynchronous request that eventually calls
// CQueryEngine::ExecQuery (see qengine.h)
//
// Parameters and return values are described in help
//
//***************************************************************************
//
HRESULT CWbemNamespace::_ExecQueryAsync(
IN ULONG uInternalFlags,
IN _IWmiFinalizer *pFnz,
IN _IWmiCoreHandle *phTask,
const BSTR strQueryFormat,
const BSTR strQuery,
long lFlags,
IWbemContext* pCtx,
IWbemObjectSink* pHandler
)
{
HRESULT hRes = CheckNs();
if (FAILED(hRes))
return hRes;
if (!Allowed(WBEM_ENABLE))
return WBEM_E_ACCESS_DENIED;
DEBUGTRACE((LOG_WBEMCORE,
"CALL CWbemNamespace::ExecQueryAsync\n"
" BSTR QueryFormat = %S\n"
" BSTR Query = %S\n"
" IWbemObjectSink* pHandler = 0x%X\n",
strQueryFormat,
strQuery,
pHandler
));
// Parameter validation.
// =====================
if (pFnz == 0 && pHandler == 0)
return WBEM_E_INVALID_PARAMETER;
if (strQueryFormat == 0 || strQuery == 0)
return WBEM_E_INVALID_PARAMETER;
if ( 0 == strQueryFormat[0] || 0 == strQuery[0])
return WBEM_E_INVALID_PARAMETER;
if (wcslen_max(strQuery,g_QueryLimit) > g_QueryLimit) return WBEM_E_QUOTA_VIOLATION;
if (lFlags & ~WBEM_FLAG_PROTOTYPE & ~WBEM_FLAG_SEND_STATUS &
~WBEM_FLAG_ENSURE_LOCATABLE & ~WBEM_FLAG_USE_AMENDED_QUALIFIERS &
~WBEM_FLAG_KEEP_SHAPE & ~WBEM_FLAG_DIRECT_READ
)
return WBEM_E_INVALID_PARAMETER;
// Create Finalizer.
// =================
IWbemObjectSink *pPseudoSink = 0;
if (pFnz == 0)
{
hRes = CreateAsyncFinalizer(pCtx, pHandler, &pFnz, &pPseudoSink);
if (FAILED(hRes))
return hRes;
}
else // borrowed finalizer
{
hRes = pFnz->NewInboundSink(0, &pPseudoSink);
if (FAILED(hRes))
return hRes;
pFnz->AddRef();
}
CReleaseMe rmPseudoSink(pPseudoSink);
CReleaseMe _2(pFnz);
// Add the request to the queue.
// =============================
// will throw CX_MemoryException
wmilib::auto_ptr<CAsyncReq_ExecQueryAsync> pReq;
pReq.reset(new CAsyncReq_ExecQueryAsync(this, strQueryFormat, strQuery, lFlags,pPseudoSink, pCtx));
if (NULL == pReq.get()) return WBEM_E_OUT_OF_MEMORY;
if ( NULL == pReq->GetContext() ) return WBEM_E_OUT_OF_MEMORY;
hRes = InitNewTask(pReq.get(), pFnz, uInternalFlags, pReq->GetContext(), pHandler);
if (FAILED(hRes)) return hRes;
rmPseudoSink.release();
hRes = ConfigMgr::EnqueueRequest(pReq.get());
if (FAILED(hRes))
{
pFnz->CancelTask ( 0 );
return hRes;
}
pReq.release();
return hRes;
}
//
//
// CWbemNamespace::_GetObjectAsync
//
// Schedules an asynchrnous request that eventuall calls Exec_GetObjectByPath.
//
// Parameters and return values are described in help
//
// throws or return
//
///////////////////////////////////////////////////////////////
HRESULT CWbemNamespace::_GetObjectAsync(
IN ULONG uInternalFlags,
IN _IWmiFinalizer *pFnz,
IN _IWmiCoreHandle *phTask,
const BSTR strObjectPath,
long lFlags,
IWbemContext* pCtx,
IWbemObjectSink* pHandler
)
{
HRESULT hRes = CheckNs();
if (FAILED(hRes))
return hRes;
DEBUGTRACE((LOG_WBEMCORE,
"CALL CWbemNamespace::GetObjectAsync\n"
" BSTR ObjectPath = %S\n"
" long lFlags = %d\n"
" IWbemObjectSink* pHandler = 0x%X\n",
strObjectPath,
lFlags,
pHandler
));
// Parameter validation.
// =====================
if (pFnz == 0 && pHandler == 0)
return WBEM_E_INVALID_PARAMETER;
if (lFlags & ~WBEM_FLAG_SEND_STATUS & ~WBEM_FLAG_USE_AMENDED_QUALIFIERS
& ~WBEM_FLAG_DIRECT_READ)
return WBEM_E_INVALID_PARAMETER;
// Create Finalizer.
// =================
IWbemObjectSink *pPseudoSink = 0;
if (pFnz == 0)
{
hRes = CreateAsyncFinalizer(pCtx, pHandler, &pFnz, &pPseudoSink);
if (FAILED(hRes))
return hRes;
}
else // borrowed finalizer
{
hRes = pFnz->NewInboundSink(0, &pPseudoSink);
if (FAILED(hRes))
return hRes;
pFnz->AddRef(); // Compensate for CReleaseMe to follow
}
CReleaseMe _1(pPseudoSink);
CReleaseMe _2(pFnz);
// Add request to the async queue.
// ===============================
wmilib::auto_ptr<CAsyncReq_GetObjectAsync> pReq;
pReq.reset(new CAsyncReq_GetObjectAsync(this, strObjectPath, lFlags, pPseudoSink, pCtx));
if (NULL == pReq.get()) return WBEM_E_OUT_OF_MEMORY;
if (NULL == pReq->GetContext()) return WBEM_E_OUT_OF_MEMORY;
hRes = InitNewTask(pReq.get(), pFnz, uInternalFlags, pReq->GetContext(), pHandler);
if (FAILED(hRes)) return hRes;
_1.release();
hRes = ConfigMgr::EnqueueRequest(pReq.get());
if (FAILED(hRes))
{
pFnz->CancelTask(0);
return hRes;
}
pReq.release();
return hRes;
}
//
//
// CWbemNamespace::ExecMethodAsync
//
// can throw
//
//////////////////////////////////////////////////////////
HRESULT CWbemNamespace::_ExecMethodAsync(
IN ULONG uInternalFlags,
IN _IWmiFinalizer *pFnz,
IN _IWmiCoreHandle *phTask,
const BSTR ObjectPath,
const BSTR MethodName,
long lFlags,
IWbemContext *pCtx,
IWbemClassObject *pInParams,
IWbemObjectSink* pHandler
)
{
HRESULT hRes = CheckNs();
if (FAILED(hRes))
return hRes;
DEBUGTRACE((LOG_WBEMCORE,
"CALL CWbemNamespace::ExecMethodAsync\n"
" BSTR ObjectPath = %S\n"
" BSTR MethodName = %S\n"
" long lFlags = %d\n"
" IWbemClassObject * pIn = 0x%X\n",
ObjectPath, MethodName, lFlags, pInParams
));
// Parameter validation.
// =====================
if (pFnz ==0 && pHandler == 0)
return WBEM_E_INVALID_PARAMETER;
if (lFlags & ~WBEM_FLAG_SEND_STATUS)
return WBEM_E_INVALID_PARAMETER;
// Create Finalizer.
// =================
IWbemObjectSink *pPseudoSink = 0;
if (pFnz == 0)
{
hRes = CreateAsyncFinalizer(pCtx, pHandler, &pFnz, &pPseudoSink);
if (FAILED(hRes))
return hRes;
}
else // borrowed finalizer
{
hRes = pFnz->NewInboundSink(0, &pPseudoSink);
if (FAILED(hRes))
return hRes;
pFnz->AddRef();
}
CReleaseMe _1(pPseudoSink);
CReleaseMe _2(pFnz);
// Add request to the async queue.
// ===============================
wmilib::auto_ptr<CAsyncReq_ExecMethodAsync> pReq;
pReq.reset(new CAsyncReq_ExecMethodAsync(this,
ObjectPath,
MethodName,
lFlags,
pInParams,
pPseudoSink,
pCtx));
if (NULL == pReq.get()) return WBEM_E_OUT_OF_MEMORY;
if ( NULL == pReq->GetContext() ) return WBEM_E_OUT_OF_MEMORY;
hRes = InitNewTask(pReq.get(), pFnz, uInternalFlags, pReq->GetContext(), pHandler);
if (FAILED(hRes)) return hRes;
_1.release();
hRes = ConfigMgr::EnqueueRequest(pReq.get());
if (FAILED(hRes))
{
pFnz->CancelTask ( 0 );
return hRes;
}
pReq.release();
return hRes;
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//
// Native sync operations
//
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//***************************************************************************
//
// CWbemNamespace::DeleteClass
//
// Calls DeleteClassAsync and waits for completion
//
// Parameters and return values are described in help
//
//***************************************************************************
//
HRESULT CWbemNamespace::DeleteClass(
const BSTR strClass,
long lFlags,
IWbemContext* pCtx,
IWbemCallResult** ppResult
)
{
HRESULT hRes = CheckNs();
if (FAILED(hRes))
return hRes;
try
{
DEBUGTRACE((LOG_WBEMCORE,
"CALL CWbemNamespace::DeleteClass"
" BSTR Class = %S\n"
" long lFlags = 0x%X\n",
strClass,
lFlags
));
// Parameter validation.
// =====================
if (lFlags
& ~WBEM_FLAG_RETURN_IMMEDIATELY
& ~WBEM_FLAG_OWNER_UPDATE
)
return WBEM_E_INVALID_PARAMETER;
if ((lFlags & WBEM_RETURN_IMMEDIATELY) && ppResult == NULL)
return WBEM_E_INVALID_PARAMETER;
// Create Finalizer.
// =================
_IWmiFinalizer *pFnz = 0;
hRes = CreateSyncFinalizer(pCtx, &pFnz);
if (FAILED(hRes))
return hRes;
CReleaseMe _1(pFnz);
ULONG uTaskType = WMICORE_TASK_DELETE_CLASS;
if (ppResult)
uTaskType |= WMICORE_TASK_TYPE_SEMISYNC;
else
uTaskType |= WMICORE_TASK_TYPE_SYNC;
// Call the async side.
// ====================
hRes = _DeleteClassAsync(uTaskType, pFnz, 0, strClass,
lFlags & ~WBEM_RETURN_IMMEDIATELY,pCtx, NULL);
if (FAILED(hRes))
return hRes;
// Check for the two return paradigms.
// ===================================
if ((lFlags & WBEM_RETURN_IMMEDIATELY) == 0)
{
HRESULT hResTemp = pFnz->GetOperationResult(0, INFINITE, &hRes);
if (FAILED(hResTemp))
return hResTemp;
}
if (ppResult)
{
hRes = pFnz->GetResultObject(0, IID_IWbemCallResult, (LPVOID *) ppResult);
}
return hRes;
}
catch(...)
{
ExceptionCounter c;
return WBEM_E_CRITICAL_ERROR;
}
}
//***************************************************************************
//
// CWbemNamespace::PutClass
//
// Calls PutClassAsync and waits for completion
//
// Parameters and return values are described in help
//
//***************************************************************************
HRESULT CWbemNamespace::PutClass(
READONLY IWbemClassObject* pObj,
long lFlags,
IWbemContext* pCtx,
NEWOBJECT IWbemCallResult** ppResult
)
{
HRESULT hRes = CheckNs();
if (FAILED(hRes))
return hRes;
CVARIANT vClass;
if (pObj)
{
hRes = pObj->Get(L"__CLASS", 0, &vClass, 0, 0);
}
DEBUGTRACE((LOG_WBEMCORE,
"CALL CWbemNamespace::PutClass\n"
" long lFlags = 0x%X\n"
" IWbemClassObject *pObj = 0x%X\n"
" __CLASS=%S\n",
lFlags,
pObj,
vClass.GetStr()
));
if (lFlags
& ~WBEM_FLAG_RETURN_IMMEDIATELY
& ~WBEM_FLAG_OWNER_UPDATE
& ~WBEM_FLAG_USE_AMENDED_QUALIFIERS
& ~WBEM_FLAG_CREATE_OR_UPDATE
& ~WBEM_FLAG_UPDATE_ONLY
& ~WBEM_FLAG_CREATE_ONLY
& ~WBEM_FLAG_UPDATE_SAFE_MODE
& ~WBEM_FLAG_UPDATE_FORCE_MODE
)
return WBEM_E_INVALID_PARAMETER;
if ((lFlags & WBEM_RETURN_IMMEDIATELY) && ppResult == NULL)
return WBEM_E_INVALID_PARAMETER;
try
{
if( ((lFlags & WBEM_FLAG_RETURN_IMMEDIATELY) == 0)&&(ppResult==NULL))
{
HANDLE hCurrentToken;
if(OpenThreadToken(GetCurrentThread(), TOKEN_READ, TRUE,
&hCurrentToken))
{
//
// Got a thread token --- cannot fast-track because otherwise we
// will have a thread token on a thread executing internal code
//
CloseHandle(hCurrentToken);
}
else if (CWbemQueue::GetCurrentRequest() == NULL)
{
if (!m_bProvider && (lFlags & WBEM_FLAG_OWNER_UPDATE))
{
return WBEM_E_INVALID_PARAMETER;
}
if (lFlags & WBEM_FLAG_OWNER_UPDATE)
{
lFlags -= WBEM_FLAG_OWNER_UPDATE;
lFlags += WBEM_FLAG_NO_EVENTS;
}
IWbemContext *pContext = pCtx ;
if (pContext)
pContext->AddRef () ;
else
{
pContext = ConfigMgr::GetNewContext();
if ( pContext == NULL )
return WBEM_E_OUT_OF_MEMORY;
}
CReleaseMe _1_pContext (pContext) ;
CSynchronousSink *pSyncSink = CSynchronousSink::Create();
if (pSyncSink == NULL) return WBEM_E_OUT_OF_MEMORY;
pSyncSink->AddRef();
CReleaseMe _2(pSyncSink);
hRes = Exec_PutClass(pObj, lFlags, pContext, pSyncSink);
// Extract the new object from the sink.
// ======================================
pSyncSink->Block();
IWbemClassObject* pErrorObj = NULL;
pSyncSink->GetStatus(&hRes, NULL, &pErrorObj);
CReleaseMe rm1(pErrorObj);
if(pErrorObj)
{
IErrorInfo* pErrorInfo = NULL;
pErrorObj->QueryInterface(IID_IErrorInfo,(void**)&pErrorInfo);
SetErrorInfo(0, pErrorInfo);
pErrorInfo->Release();
}
return hRes;
}
}
// Create Finalizer.
// =================
_IWmiFinalizer *pFnz = 0;
hRes = CreateSyncFinalizer(pCtx, &pFnz);
if (FAILED(hRes))
return hRes;
CReleaseMe _1(pFnz);
ULONG uTaskType = WMICORE_TASK_PUT_CLASS;
if (ppResult)
uTaskType |= WMICORE_TASK_TYPE_SEMISYNC;
else
uTaskType |= WMICORE_TASK_TYPE_SYNC;
// Do the work elsewhere.
// ======================
hRes = _PutClassAsync(uTaskType, pFnz, 0, pObj, lFlags & ~WBEM_RETURN_IMMEDIATELY,
pCtx, NULL);
if (FAILED(hRes))
return hRes;
// Check for the two return paradigms.
// ===================================
if ((lFlags & WBEM_RETURN_IMMEDIATELY) == 0)
{
HRESULT hResTemp = pFnz->GetOperationResult(0, INFINITE, &hRes);
if (FAILED(hResTemp))
return hResTemp;
}
if (ppResult)
{
hRes = pFnz->GetResultObject(0, IID_IWbemCallResult, (LPVOID *) ppResult);
}
return hRes;
}
catch(...) // this interface calls the Exec_[MetrhodName] straight
{
ExceptionCounter c;
return WBEM_E_CRITICAL_ERROR;
}
}
//***************************************************************************
//
// CWbemNamespace::CancelAsyncRequest.
//
// Currently a noop, eventually this function will cancel an asynchrnous
// request based on the handle value it returned.
//
// Parameters and return values are described in help
//
//***************************************************************************
HRESULT CWbemNamespace::CancelAsyncCall(IWbemObjectSink* pSink)
{
HRESULT hRes = CheckNs();
if (FAILED(hRes))
return hRes;
// Note that LOMEM_CHECK is not needed or wanted here
if (pSink == NULL)
return WBEM_E_INVALID_PARAMETER;
// Quickly cancel via Arbitrator.
// ===============================
if (m_pArb)
{
hRes = m_pArb->CancelTasksBySink(WMIARB_CALL_CANCELLED_CLIENT, IID_IWbemObjectSink, pSink);
}
return hRes ;
}
//***************************************************************************
//
// CWbemNamespace::PutInstance
//
// Calls PutInstanceAsync and waits for completion
//
// Parameters and return values are described in help
//
//***************************************************************************
HRESULT CWbemNamespace::PutInstance(
IWbemClassObject* pInst,
long lFlags,
IWbemContext* pCtx,
IWbemCallResult** ppResult
)
{
HRESULT hRes = CheckNs();
if (FAILED(hRes))
return hRes;
// Parameter validation.
// =====================
if (lFlags
& ~WBEM_RETURN_IMMEDIATELY
& ~WBEM_FLAG_USE_AMENDED_QUALIFIERS
& ~WBEM_FLAG_OWNER_UPDATE
& ~WBEM_FLAG_CREATE_ONLY
& ~WBEM_FLAG_UPDATE_ONLY
& ~WBEM_FLAG_CREATE_OR_UPDATE
)
return WBEM_E_INVALID_PARAMETER;
try
{
DEBUGTRACE((LOG_WBEMCORE,
"CALL CWbemNamespace::PutInstance"
" long lFlags = 0x%X\n"
" IWbemClassObject *pInst = 0x%X\n",
lFlags,
pInst));
if( ((lFlags & WBEM_FLAG_RETURN_IMMEDIATELY) == 0)&&(ppResult==NULL))
{
// trick for allowing setup to set the SD
AutoRevertSecTlsFlag RevSec ( (LPVOID) 1 );
if ( IsNtSetupRunning() )
{
RevSec.SetSecTlsFlag ( (LPVOID) 0 );
}
HANDLE hCurrentToken;
if(OpenThreadToken(GetCurrentThread(), TOKEN_READ, TRUE,
&hCurrentToken))
{
//
// Got a thread token --- cannot fast-track because otherwise we
// will have a thread token on a thread executing internal code
//
CloseHandle(hCurrentToken);
}
else if (CWbemQueue::GetCurrentRequest() == NULL)
{
IWbemContext *pContext = pCtx ;
if (pContext)
pContext->AddRef () ;
else
{
pContext = ConfigMgr::GetNewContext();
if ( pContext == NULL )
return WBEM_E_OUT_OF_MEMORY;
}
CReleaseMe _1_pContext (pContext) ;
CSynchronousSink *pSyncSink = CSynchronousSink::Create();
if (pSyncSink == NULL)
return WBEM_E_OUT_OF_MEMORY;
pSyncSink->AddRef();
CReleaseMe _2(pSyncSink);
if (!m_bProvider && (lFlags & WBEM_FLAG_OWNER_UPDATE))
{
return WBEM_E_INVALID_PARAMETER;
}
if (lFlags & WBEM_FLAG_OWNER_UPDATE)
{
lFlags -= WBEM_FLAG_OWNER_UPDATE;
lFlags += WBEM_FLAG_NO_EVENTS;
}
hRes = Exec_PutInstance(pInst, lFlags, pContext, pSyncSink);
// Extract the new object from the sink.
// ======================================
pSyncSink->Block();
IWbemClassObject* pErrorObj = NULL;
pSyncSink->GetStatus(&hRes, NULL, &pErrorObj);
CReleaseMe rm1(pErrorObj);
if(pErrorObj)
{
IErrorInfo* pErrorInfo = NULL;
pErrorObj->QueryInterface(IID_IErrorInfo,
(void**)&pErrorInfo);
SetErrorInfo(0, pErrorInfo);
pErrorInfo->Release();
}
return hRes;
}
}
if ((lFlags & WBEM_RETURN_IMMEDIATELY) && ppResult == NULL)
return WBEM_E_INVALID_PARAMETER;
// Create Finalizer.
// =================
_IWmiFinalizer *pFnz = 0;
hRes = CreateSyncFinalizer(pCtx, &pFnz);
if (FAILED(hRes))
return hRes;
CReleaseMe _1(pFnz);
ULONG uTaskType = WMICORE_TASK_PUT_INSTANCE;
if (ppResult)
uTaskType |= WMICORE_TASK_TYPE_SEMISYNC;
else
uTaskType |= WMICORE_TASK_TYPE_SYNC;
// Do the work elsewhere.
// ======================
hRes = _PutInstanceAsync(uTaskType, pFnz, 0, pInst,
lFlags & ~WBEM_RETURN_IMMEDIATELY,
pCtx, NULL);
if (FAILED(hRes))
return hRes;
// Check for the two return paradigms.
// ===================================
if ((lFlags & WBEM_RETURN_IMMEDIATELY) == 0)
{
HRESULT hResTemp = pFnz->GetOperationResult(0, INFINITE, &hRes);
if (FAILED(hResTemp))
return hResTemp;
}
if (ppResult)
{
hRes = pFnz->GetResultObject(0, IID_IWbemCallResult, (LPVOID *) ppResult);
}
return hRes;
}
catch(...) // this interfaces calls the Exec_[MethodName]
{
ExceptionCounter c;
return WBEM_E_CRITICAL_ERROR;
}
}
//***************************************************************************
//
// CWbemNamespace::DeleteInstance
//
// Calls DeleteInstanceAsync and waits for completion
//
// Parameters and return values are described in help
//
//***************************************************************************
HRESULT CWbemNamespace::DeleteInstance(
READONLY const BSTR strObjectPath,
long lFlags,
IWbemContext* pCtx,
IWbemCallResult** ppResult
)
{
HRESULT hRes = CheckNs();
if (FAILED(hRes))
return hRes;
DEBUGTRACE((LOG_WBEMCORE,
"CALL CWbemNamespace::DeleteInstance\n"
" BSTR ObjectPath = %S\n"
" long lFlags = %d\n",
strObjectPath, lFlags
));
if (lFlags & ~WBEM_FLAG_RETURN_IMMEDIATELY &~ WBEM_FLAG_OWNER_UPDATE)
return WBEM_E_INVALID_PARAMETER;
if((lFlags & WBEM_RETURN_IMMEDIATELY) && ppResult == NULL)
return WBEM_E_INVALID_PARAMETER;
// Create Finalizer.
// =================
_IWmiFinalizer *pFnz = 0;
hRes = CreateSyncFinalizer(pCtx, &pFnz);
if (FAILED(hRes))
return hRes;
CReleaseMe _1(pFnz);
ULONG uTaskType = WMICORE_TASK_DELETE_INSTANCE;
if (ppResult)
uTaskType |= WMICORE_TASK_TYPE_SEMISYNC;
else
uTaskType |= WMICORE_TASK_TYPE_SYNC;
// Do the work elsewhere.
// ======================
hRes = _DeleteInstanceAsync(uTaskType, pFnz, 0, strObjectPath, lFlags & ~WBEM_RETURN_IMMEDIATELY,
pCtx, NULL);
if (FAILED(hRes))
return hRes;
// Check for the two return paradigms.
// ===================================
if ((lFlags & WBEM_RETURN_IMMEDIATELY) == 0)
{
HRESULT hResTemp = pFnz->GetOperationResult(0,INFINITE, &hRes);
if (FAILED(hResTemp))
return hResTemp;
}
if (ppResult)
{
hRes = pFnz->GetResultObject(0, IID_IWbemCallResult, (LPVOID *) ppResult);
}
return hRes;
}
//***************************************************************************
//
// CWbemNamespace::GetObject
//
// Calls GetObjectAsync and waits for completion
//
// Parameters and return values are described in help
//
//***************************************************************************
HRESULT CWbemNamespace::GetObject(
READONLY const BSTR strObjectPath,
long lFlags,
IWbemContext* pCtx,
NEWOBJECT IWbemClassObject** ppObj,
NEWOBJECT IWbemCallResult** ppResult
)
{
HRESULT hRes = CheckNs();
if (FAILED(hRes))
return hRes;
if (!Allowed(WBEM_ENABLE))
return WBEM_E_ACCESS_DENIED;
DEBUGTRACE((LOG_WBEMCORE,
"CALL CWbemNamespace::GetObject\n"
" BSTR ObjectPath = %S\n"
" long lFlags = %d\n"
" IWbemClassObject ** pObj = 0x%X\n",
strObjectPath,
lFlags,
ppObj
));
if (ppObj)
*ppObj = NULL;
if (lFlags
& ~WBEM_FLAG_RETURN_IMMEDIATELY
& ~WBEM_FLAG_USE_AMENDED_QUALIFIERS
& ~WBEM_FLAG_DIRECT_READ
)
return WBEM_E_INVALID_PARAMETER;
if ((lFlags & WBEM_RETURN_IMMEDIATELY) && ppResult == NULL)
return WBEM_E_INVALID_PARAMETER;
try
{
if( ((lFlags & WBEM_FLAG_RETURN_IMMEDIATELY) == 0)&&(ppResult==NULL))
{
//
// This is special case GetObject synchronous. We dont want to allow this unless,
// we're running setup.
//
AutoRevertSecTlsFlag RevSec ( (LPVOID) 1 );
if ( IsNtSetupRunning() )
{
RevSec.SetSecTlsFlag ( (LPVOID) 0 );
}
HANDLE hCurrentToken;
if(OpenThreadToken(GetCurrentThread(), TOKEN_READ, TRUE,
&hCurrentToken))
{
//
// Got a thread token --- cannot fast-track because otherwise we
// will have a thread token on a thread executing internal code
//
CloseHandle(hCurrentToken);
}
else if (CWbemQueue::GetCurrentRequest() == NULL)
{
IWbemContext *pContext = pCtx ;
if (pContext)
pContext->AddRef () ;
else
{
pContext = ConfigMgr::GetNewContext();
if ( pContext == NULL )
return WBEM_E_OUT_OF_MEMORY;
}
CReleaseMe _1_pContext (pContext) ;
CSynchronousSink *pSyncSink = CSynchronousSink::Create();
if (pSyncSink == NULL)
return WBEM_E_OUT_OF_MEMORY;
pSyncSink->AddRef();
CReleaseMe _2(pSyncSink);
hRes = Exec_GetObject(strObjectPath, lFlags, pContext, pSyncSink);
//if (FAILED(hRes))
//{
// return hRes;
//}
// Extract the new object from the sink.
// ======================================
pSyncSink->Block();
IWbemClassObject* pErrorObj = NULL;
pSyncSink->GetStatus(&hRes, NULL, &pErrorObj);
CReleaseMe rm1(pErrorObj);
if(pErrorObj)
{
IErrorInfo* pErrorInfo = NULL;
pErrorObj->QueryInterface(IID_IErrorInfo,
(void**)&pErrorInfo);
SetErrorInfo(0, pErrorInfo);
pErrorInfo->Release();
}
if (SUCCEEDED(hRes))
{
if(pSyncSink->GetObjects().GetSize() != 1)
return WBEM_E_CRITICAL_ERROR;
// Only access the returned object if ppObj is non-NULL.
if ( NULL != ppObj )
{
*ppObj = pSyncSink->GetObjects()[0];
(*ppObj)->AddRef();
}
}
return hRes;
}
}
// Create Finalizer.
// =================
_IWmiFinalizer *pFnz = 0;
hRes = CreateSyncFinalizer(pCtx, &pFnz);
if (FAILED(hRes))
return hRes;
CReleaseMe _1(pFnz);
ULONG uTaskType = WMICORE_TASK_GET_OBJECT;
if (ppResult)
uTaskType |= WMICORE_TASK_TYPE_SEMISYNC;
else
uTaskType |= WMICORE_TASK_TYPE_SYNC;
// Do the work elsewhere.
// ======================
hRes = _GetObjectAsync(uTaskType, pFnz, 0, strObjectPath, lFlags & ~WBEM_RETURN_IMMEDIATELY,
pCtx, NULL);
if (FAILED(hRes))
{
return hRes;
}
// Check for the two return paradigms.
// ===================================
if ((lFlags & WBEM_RETURN_IMMEDIATELY) == 0)
{
HRESULT hResTemp = pFnz->GetOperationResult(0, INFINITE, &hRes);
if (FAILED(hResTemp))
return hResTemp;
if (FAILED(hRes))
return hRes;
}
if (ppResult)
{
hRes = pFnz->GetResultObject(0, IID_IWbemCallResult, (LPVOID *) ppResult);
if (FAILED(hRes))
{
return hRes;
}
if (ppObj && ((lFlags & WBEM_RETURN_IMMEDIATELY) == 0))
hRes = (*ppResult)->GetResultObject(INFINITE, ppObj);
}
else if (ppObj && ((lFlags & WBEM_RETURN_IMMEDIATELY) == 0))
{
hRes = pFnz->GetResultObject(0, IID_IWbemClassObject, (LPVOID *) ppObj);
}
return hRes;
}
catch(...) // this interface goes to the Exec_[MethodName straight]
{
ExceptionCounter c;
return WBEM_E_CRITICAL_ERROR;
}
}
//***************************************************************************
//
// CWbemNamespace::ExecMethod
//
//***************************************************************************
HRESULT CWbemNamespace::ExecMethod(
const BSTR ObjectPath,
const BSTR MethodName,
long lFlags,
IWbemContext *pCtx,
IWbemClassObject *pInParams,
IWbemClassObject **ppOutParams,
IWbemCallResult **ppResult
)
{
HRESULT hRes = CheckNs();
if (FAILED(hRes))
return hRes;
DEBUGTRACE((LOG_WBEMCORE,
"CALL CWbemNamespace::ExecMethod\n"
" BSTR ObjectPath = %S\n"
" BSTR MethodName = %S\n"
" long lFlags = %d\n"
" IWbemClassObject * pIn = 0x%X\n",
ObjectPath, MethodName, lFlags, pInParams
));
// Parameter validation.
// =====================
if (ppOutParams)
*ppOutParams = NULL;
if (lFlags & ~WBEM_FLAG_RETURN_IMMEDIATELY)
return WBEM_E_INVALID_PARAMETER;
// Create Finalizer.
// =================
_IWmiFinalizer *pFnz = 0;
hRes = CreateSyncFinalizer(pCtx, &pFnz);
if (FAILED(hRes))
return hRes;
CReleaseMe _1(pFnz);
ULONG uTaskType = WMICORE_TASK_EXEC_METHOD;
if (ppResult)
uTaskType |= WMICORE_TASK_TYPE_SEMISYNC;
else
uTaskType |= WMICORE_TASK_TYPE_SYNC;
// Do the work elsewhere.
// ======================
hRes = _ExecMethodAsync(uTaskType, pFnz, 0, ObjectPath, MethodName,
lFlags & ~WBEM_RETURN_IMMEDIATELY, pCtx, pInParams, NULL);
if (FAILED(hRes))
return hRes;
// Check for the two return paradigms.
// ===================================
if ((lFlags & WBEM_RETURN_IMMEDIATELY) == 0)
{
HRESULT hResTemp = pFnz->GetOperationResult(0, INFINITE, &hRes);
if (FAILED(hResTemp))
return hResTemp;
if (FAILED(hRes))
return hRes;
if (ppResult)
{
hRes = pFnz->GetResultObject(0, IID_IWbemCallResult, (LPVOID *) ppResult);
if (FAILED(hRes))
return hRes;
if (ppOutParams)
{
hRes = (*ppResult)->GetResultObject(INFINITE, ppOutParams);
if (hRes == WBEM_E_NOT_FOUND) //If there was no object we still return success!
hRes = WBEM_S_NO_ERROR;
}
}
else
{
hRes = pFnz->GetResultObject(0, IID_IWbemClassObject, (LPVOID *) ppOutParams);
if (hRes == WBEM_E_NOT_FOUND) //If there was no object we still return success!
hRes = WBEM_S_NO_ERROR;
}
}
else
{
//
// If we have a call result pointer we should try to use it
//
if ( ppResult )
{
hRes = pFnz->GetResultObject(0, IID_IWbemCallResult, (LPVOID *) ppResult);
if (hRes == WBEM_E_NOT_FOUND) //If there was no object we still return success!
hRes = WBEM_S_NO_ERROR;
}
else // semysync and nobody interested
{
pFnz->CancelTask(0);
hRes = WBEM_S_NO_ERROR;
}
}
return hRes;
}
//***************************************************************************
//
// CWbemNamespace::CreateInstanceEnum
//
// Calls CreateInstanceEnumAsync and waits for completion
//
// Parameters and return values are described in help
//
//***************************************************************************
HRESULT CWbemNamespace::CreateInstanceEnum(
const BSTR strClass,
long lFlags,
IWbemContext* pCtx,
IEnumWbemClassObject** ppEnum
)
{
HRESULT hRes = CheckNs();
if (FAILED(hRes))
return hRes;
DEBUGTRACE((LOG_WBEMCORE,
"CALL CWbemNamespace::CreateInstanceEnum\n"
" long lFlags = 0x%X\n"
" BSTR Class = %S\n"
" IEnumWbemClassObject **pEnum = 0x%X\n",
lFlags,
strClass,
ppEnum
));
// Validate parameters
// ===================
if (lFlags
& ~WBEM_RETURN_IMMEDIATELY
& ~WBEM_FLAG_FORWARD_ONLY
& ~WBEM_FLAG_DEEP
& ~WBEM_FLAG_SHALLOW
& ~WBEM_FLAG_USE_AMENDED_QUALIFIERS
& ~WBEM_FLAG_DIRECT_READ
)
return WBEM_E_INVALID_PARAMETER;
if (ppEnum == NULL)
return WBEM_E_INVALID_PARAMETER;
*ppEnum = NULL;
// Create Finalizer.
// =================
_IWmiFinalizer *pFnz = 0;
hRes = CreateSyncFinalizer(pCtx, &pFnz);
if (FAILED(hRes))
return hRes;
CReleaseMe _1(pFnz);
ULONG uTaskType = WMICORE_TASK_ENUM_INSTANCES;
if (lFlags & WBEM_RETURN_IMMEDIATELY)
uTaskType |= WMICORE_TASK_TYPE_SEMISYNC;
else
uTaskType |= WMICORE_TASK_TYPE_SYNC;
// Do the work.
// ============
hRes = _CreateInstanceEnumAsync(uTaskType, pFnz, 0, strClass,
lFlags & ~WBEM_RETURN_IMMEDIATELY & ~WBEM_FLAG_FORWARD_ONLY,
pCtx, NULL);
if (FAILED(hRes))
return hRes;
if ((lFlags & WBEM_RETURN_IMMEDIATELY) == 0)
pFnz->GetOperationResult(0, INFINITE, &hRes);
if (SUCCEEDED(hRes))
{
IEnumWbemClassObject* pEnum = NULL;
HRESULT hResTemp = pFnz->GetResultObject(lFlags, IID_IEnumWbemClassObject, (LPVOID*)&pEnum);
if (FAILED(hResTemp))
return hResTemp;
CReleaseMe _2(pEnum);
*ppEnum = pEnum;
pEnum->AddRef(); // counteract CReleaseMe
}
return hRes;
}
//***************************************************************************
//
// CWbemNamespace::CreateClassEnum
//
// Invokes CreateClassEnumAsync and waits for completion. Actual work is
// performed in Exec_CreateClassEnum.
//
// Parameters and return values are described in help
//
//***************************************************************************
HRESULT CWbemNamespace::CreateClassEnum(
const BSTR strParent,
long lFlags,
IWbemContext* pCtx,
IEnumWbemClassObject **ppEnum
)
{
HRESULT hRes = CheckNs();
if (FAILED(hRes))
return hRes;
DEBUGTRACE((LOG_WBEMCORE,
"CALL CWbemNamespace::CreateClassEnum\n"
" BSTR Parent = %S\n"
" long lFlags = 0x%X\n"
" IEnumWbemClassObject = 0x%X\n",
strParent,
lFlags,
ppEnum
));
// Validate parameters
// ===================
if (lFlags
& ~WBEM_FLAG_DEEP
& ~WBEM_FLAG_SHALLOW
& ~WBEM_FLAG_USE_AMENDED_QUALIFIERS
& ~WBEM_FLAG_RETURN_IMMEDIATELY
& ~WBEM_FLAG_FORWARD_ONLY
)
return WBEM_E_INVALID_PARAMETER;
if (ppEnum == NULL)
return WBEM_E_INVALID_PARAMETER;
*ppEnum = NULL;
// Create Finalizer.
// =================
_IWmiFinalizer *pFnz = 0;
hRes = CreateSyncFinalizer(pCtx, &pFnz);
if (FAILED(hRes))
return hRes;
CReleaseMe _1(pFnz);
ULONG uTaskType = WMICORE_TASK_ENUM_CLASSES;
if (lFlags & WBEM_RETURN_IMMEDIATELY)
uTaskType |= WMICORE_TASK_TYPE_SEMISYNC;
else
uTaskType |= WMICORE_TASK_TYPE_SYNC;
// Do the work.
// ============
hRes = _CreateClassEnumAsync(uTaskType, pFnz, 0, strParent,
lFlags & ~WBEM_RETURN_IMMEDIATELY & ~WBEM_FLAG_FORWARD_ONLY,
pCtx, NULL);
if (FAILED(hRes))
return hRes;
if ((lFlags & WBEM_RETURN_IMMEDIATELY) == 0)
pFnz->GetOperationResult(0, INFINITE, &hRes);
if (SUCCEEDED(hRes))
{
IEnumWbemClassObject* pEnum = NULL;
HRESULT hResTemp = pFnz->GetResultObject(lFlags, IID_IEnumWbemClassObject, (LPVOID*)&pEnum);
if (FAILED(hResTemp))
return hResTemp;
CReleaseMe _2(pEnum);
*ppEnum = pEnum;
pEnum->AddRef(); // Counteract CReleaseMe
}
return hRes;
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWbemNamespace::ExecQuery(
READONLY const BSTR strQueryFormat,
READONLY const BSTR strQuery,
long lFlags,
IWbemContext* pCtx,
NEWOBJECT IEnumWbemClassObject** ppEnum
)
{
HRESULT hRes = CheckNs();
if (FAILED(hRes))
return hRes;
DEBUGTRACE((LOG_WBEMCORE,
"CALL CWbemNamespace::ExecQuery\n"
" BSTR QueryFormat = %S\n"
" BSTR Query = %S\n"
" IEnumWbemClassObject **pEnum = 0x%X\n",
strQueryFormat,
strQuery,
ppEnum
));
// Validate parameters
// ===================
if (lFlags
& ~WBEM_FLAG_PROTOTYPE
& ~WBEM_FLAG_ENSURE_LOCATABLE
& ~WBEM_FLAG_USE_AMENDED_QUALIFIERS
& ~WBEM_FLAG_KEEP_SHAPE
& ~WBEM_RETURN_IMMEDIATELY
& ~WBEM_FLAG_FORWARD_ONLY
& ~WBEM_FLAG_DIRECT_READ
)
return WBEM_E_INVALID_PARAMETER;
if (ppEnum == NULL)
return WBEM_E_INVALID_PARAMETER;
try
{
*ppEnum = NULL;
// Create Finalizer.
_IWmiFinalizer *pFnz = 0;
hRes = CreateSyncFinalizer(pCtx, &pFnz);
if (FAILED(hRes))
return hRes;
CReleaseMe _1(pFnz);
ULONG uTaskType = WMICORE_TASK_EXEC_QUERY;
if (lFlags & WBEM_RETURN_IMMEDIATELY)
uTaskType |= WMICORE_TASK_TYPE_SEMISYNC;
else
uTaskType |= WMICORE_TASK_TYPE_SYNC;
// Do the work.
// ============
hRes = _ExecQueryAsync(uTaskType, pFnz, 0, strQueryFormat, strQuery,
lFlags & ~WBEM_RETURN_IMMEDIATELY & ~WBEM_FLAG_FORWARD_ONLY,
pCtx, NULL);
if (FAILED(hRes))
return hRes;
if ((lFlags & WBEM_RETURN_IMMEDIATELY) == 0)
pFnz->GetOperationResult(0, INFINITE, &hRes);
if (SUCCEEDED(hRes))
{
IEnumWbemClassObject* pEnum = NULL;
HRESULT hResTemp = pFnz->GetResultObject(lFlags, IID_IEnumWbemClassObject, (LPVOID*)&pEnum);
if (FAILED(hResTemp))
return hResTemp;
CReleaseMe _2(pEnum);
*ppEnum = pEnum;
pEnum->AddRef(); // Counteract CReleaseMe
}
return hRes;
}
catch(CX_MemoryException &)
{
return WBEM_E_OUT_OF_MEMORY;
}
catch(...)
{
ExceptionCounter c;
return WBEM_E_CRITICAL_ERROR;
}
}
//***************************************************************************
//
// CWbemNamespace::QueryObjectSink
//
// Returns the pointer to the ESS event handler. Clients can use this pointer
// to supply events to WINMGMT. NOTE: this pointer will be NULL if ESS is
// disabled (see cfgmgr.h).
//
// Parameters and return values are described in help
//
//***************************************************************************
HRESULT CWbemNamespace::QueryObjectSink(
long lFlags,
IWbemObjectSink** ppHandler
)
{
HRESULT hRes = CheckNs();
if (FAILED(hRes))
return hRes;
if (!Allowed(WBEM_FULL_WRITE_REP))
return WBEM_E_ACCESS_DENIED;
if (ppHandler == NULL)
return WBEM_E_INVALID_PARAMETER;
*ppHandler = NULL;
if (lFlags != 0)
return WBEM_E_INVALID_PARAMETER;
IWbemEventSubsystem_m4* pEss = ConfigMgr::GetEssSink();
if (pEss)
{
CReleaseMe rm_(pEss);
CWbemPtr<IWbemObjectSink> pEssSink;
hRes = pEss->GetNamespaceSink(m_pThisNamespaceFull, &pEssSink);
if ( FAILED(hRes)) return hRes;
CWbemPtr<CSecureEssNamespaceSink> pSecureSink = new CSecureEssNamespaceSink(this,pEssSink);
if ( pSecureSink == NULL )
return WBEM_E_OUT_OF_MEMORY;
hRes = pSecureSink->QueryInterface( IID_IWbemObjectSink,
(void**)ppHandler );
return hRes;
}
else
{
return WBEM_E_NOT_SUPPORTED;
}
}
//***************************************************************************
//
// CWbemNamespace::OpenNamespace
//
// Opens a child namespace of this one. Username, password, locale id,
// flags and error object parameters are ignored.
//
// Parameters:
//
// BSTR NsPath Relative path to the namespace
// BSTR User Reserved, must be NULL.
// BSTR Password Reserved, must be NULL.
// long lLocaleId Reserved, must be NULL.
// long lFlags Reserved, must be NULL.
// IWbemServices **pNewContext Destination for the new namespace pointer.
// Must be released by the caller.
// IWbemClassObject** ppErrorObj Reserved, must be NULL.
//
// RETURN VALUES:
//
// WBEM_S_NO_ERROR On success
// WBEM_E_INVALID_PARAMETER Invalid name.
//
//***************************************************************************
HRESULT CWbemNamespace::OpenNamespace(
const BSTR NsPath,
long lFlags,
IWbemContext* pCtx,
IWbemServices **ppNewNamespace,
IWbemCallResult **ppResult
)
{
HRESULT hRes = CheckNs();
if (FAILED(hRes))
return hRes;
DEBUGTRACE((LOG_WBEMCORE,
"CALL CWbemNamespace::OpenNamespace\n"
" BSTR NsPath = %S\n"
" long lFlags = %d\n"
" IWbemContext* pCtx = 0x%X\n"
" IWbemServices **pNewContext = 0x%X\n",
NsPath,
lFlags,
pCtx,
ppNewNamespace
));
// Parameter validation.
// =====================
try
{
if (NsPath == 0 || wcslen(NsPath) == 0 || // SEC:REVIEWED 2002-03-22 : OK
(ppNewNamespace == NULL && ppResult == NULL))
{
return WBEM_E_INVALID_PARAMETER;
}
if (ppNewNamespace == NULL && (lFlags & WBEM_RETURN_IMMEDIATELY) == 0)
{
return WBEM_E_INVALID_PARAMETER;
}
if ((lFlags & WBEM_RETURN_IMMEDIATELY) && ppNewNamespace)
return WBEM_E_INVALID_PARAMETER;
if(ppNewNamespace)
*ppNewNamespace = NULL;
if(ppResult)
*ppResult = NULL;
if((lFlags & ~WBEM_RETURN_IMMEDIATELY & ~WBEM_FLAG_USE_AMENDED_QUALIFIERS & ~WBEM_FLAG_CONNECT_REPOSITORY_ONLY) != 0)
return WBEM_E_INVALID_PARAMETER;
bool bWin9XLocalSecurity = false;
// If here, we found the object, so we open the
// corresponding namespace.
// ============================================
WString NewNs = m_pThisNamespace;
NewNs += L"\\";
NewNs += NsPath;
CCallResult* pResult = new CCallResult;
if(pResult == NULL) return WBEM_E_OUT_OF_MEMORY;
CReleaseMe rmResult(pResult);
// Schedule a request and wait
// ===========================
bool bForClient = m_bForClient ? true : false;
wmilib::auto_ptr<CAsyncReq_OpenNamespace> pReq;
pReq.reset( new CAsyncReq_OpenNamespace(this,
NewNs,
(bWin9XLocalSecurity) ? SecFlagWin9XLocal : lFlags & WBEM_FLAG_CONNECT_REPOSITORY_ONLY,
(bWin9XLocalSecurity) ? m_dwPermission : 0,
pCtx, pResult, bForClient));
if (NULL == pReq.get()) return WBEM_E_OUT_OF_MEMORY;
hRes = ConfigMgr::EnqueueRequest(pReq.get());
if (FAILED(hRes)) return hRes;
pReq.release(); // ownership transferred to queue
if (ppResult)
{
*ppResult = pResult;
pResult->AddRef();
}
if ((lFlags & WBEM_RETURN_IMMEDIATELY) == 0)
{
hRes = pResult->GetResultServices(INFINITE, ppNewNamespace);
}
return hRes;
}
catch(...)
{
ExceptionCounter c;
return WBEM_E_FAILED;
}
}
//***************************************************************************
//
//***************************************************************************
//
HRESULT CWbemNamespace::DeleteObject(
IN const BSTR strObjectPath,
IN long lFlags,
IN IWbemContext __RPC_FAR *pCtx,
/* [unique][in][out] */ IWbemCallResult __RPC_FAR *__RPC_FAR *ppCallResult
)
{
HRESULT hRes;
ULONGLONG uInf;
// Parse the path and determine if a class or instance.
IWbemPath *pPath = ConfigMgr::GetNewPath();
CReleaseMe _(pPath);
hRes = pPath->SetText(WBEMPATH_CREATE_ACCEPT_ALL, strObjectPath);
if (FAILED(hRes))
return hRes;
hRes = pPath->GetInfo(0, &uInf);
if (FAILED(hRes))
return hRes;
if (uInf & WBEMPATH_INFO_IS_CLASS_REF)
return DeleteClass(strObjectPath, lFlags, pCtx, ppCallResult);
else if (uInf & WBEMPATH_INFO_IS_INST_REF)
return DeleteInstance(strObjectPath, lFlags, pCtx, ppCallResult);
else
return WBEM_E_INVALID_PARAMETER;
}
//***************************************************************************
//
//***************************************************************************
//
HRESULT CWbemNamespace::ExecSyncQuery(
IN LPWSTR pszQuery,
IN IWbemContext *pCtx,
IN LONG lFlags,
OUT CFlexArray &aDest
)
{
HRESULT hRes;
CSynchronousSink* pSink = CSynchronousSink::Create();
if (NULL == pSink) return WBEM_E_OUT_OF_MEMORY;
pSink->AddRef();
CReleaseMe _1(pSink);
hRes = CQueryEngine::ExecQuery(this, L"WQL", pszQuery, lFlags, pCtx, pSink);
if (FAILED(hRes)) return hRes;
pSink->Block();
pSink->GetStatus(&hRes, NULL, NULL);
if (FAILED(hRes)) return hRes;
aDest.Bind(pSink->GetObjects().GetArray());
return WBEM_S_NO_ERROR;
}
//***************************************************************************
//
// CWbemNamespace::MapAssocRefsToClasses
//
// Analyzes the association and determines which reference properties
// point to which endpoints. <pszAssocRef1> is the ref property
// which can point to instances of <pClsDef1> and <pszAssocRef2> is
// the property which can point to instances of <pClsDef2>.
//
//***************************************************************************
//
HRESULT CWbemNamespace::MapAssocRefsToClasses(
IN IWbemClassObject *pAssocClass,
IN IWbemClassObject *pClsDef1,
IN IWbemClassObject *pClsDef2,
wmilib::auto_buffer<WCHAR> & pszAssocRef1,
wmilib::auto_buffer<WCHAR> & pszAssocRef2)
{
HRESULT hRes;
// Note 97: Not valid for ternary assoc types
// or derived types.
// ===========================================
// For each ref property, see if it can point to one of the endpoints.
// ===================================================================
pAssocClass->BeginEnumeration(WBEM_FLAG_REFS_ONLY);
while (1)
{
BSTR strPropName = 0;
hRes = pAssocClass->Next(0,&strPropName,0,0,0);
CSysFreeMe _1(strPropName);
if (hRes == WBEM_S_NO_MORE_DATA) break;
hRes = CAssocQuery::RoleTest(pClsDef1, pAssocClass, this, strPropName, ROLETEST_MODE_CIMREF_TYPE);
if (SUCCEEDED(hRes))
{
pszAssocRef1.reset(Macro_CloneLPWSTR(strPropName));
if (NULL == pszAssocRef1.get()) return WBEM_E_OUT_OF_MEMORY;
continue;
}
hRes = CAssocQuery::RoleTest(pClsDef2, pAssocClass, this, strPropName, ROLETEST_MODE_CIMREF_TYPE);
if (SUCCEEDED(hRes))
{
pszAssocRef2.reset(Macro_CloneLPWSTR(strPropName));
if (NULL == pszAssocRef2.get()) return WBEM_E_OUT_OF_MEMORY;
continue;
}
} // Enum of ref properties
pAssocClass->EndEnumeration();
if (NULL == pszAssocRef1.get() ||NULL == pszAssocRef2.get())
{
pszAssocRef1.reset(NULL);
pszAssocRef2.reset(NULL);
return WBEM_E_FAILED;
}
return WBEM_S_NO_ERROR;
}
//***************************************************************************
//
//***************************************************************************
//
HRESULT CWbemNamespace::BuildAssocTriads(
IN IWbemClassObject *pAssocClass, // Assoc class
IN IWbemClassObject *pClsDef1, // Class for EP1
IN IWbemClassObject *pClsDef2, // Class for EP2
IN LPWSTR pszJoinProp1, // Matching prop in EP1
IN LPWSTR pszJoinProp2, // Matching prop in EP2
IN LPWSTR pszAssocRef1, // Prop which points to EP1
IN LPWSTR pszAssocRef2, // Prop which points to EP2
IN CFlexArray &aEp1, // EP1 instances
IN CFlexArray &aEp2, // EP2 instances
IN OUT CFlexArray &aTriads // OUT : Triad list
)
{
HRESULT hRes = WBEM_S_NO_ERROR;
if (pszJoinProp1 == 0 || pszJoinProp2 == 0 || pAssocClass == 0 ||
pszAssocRef1 == 0 || pszAssocRef2 == 0)
return WBEM_E_INVALID_PARAMETER;
// Do the matching.
// ================
for (int i = 0; i < aEp1.Size(); i++)
{
IWbemClassObject *pObj1 = (IWbemClassObject *) aEp1[i];
CVARIANT v1;
if (FAILED(hRes = pObj1->Get(pszJoinProp1, 0, &v1, 0, 0))) return hRes;
for (int i2 = 0; i2 < aEp2.Size(); i2++)
{
BOOL bMatch = FALSE;
IWbemClassObject *pObj2 = (IWbemClassObject *) aEp2[i2];
CVARIANT v2;
pObj2->Get(pszJoinProp2, 0, &v2, 0, 0);
if (V_VT(&v1) == VT_I4 && V_VT(&v2) == VT_I4)
{
if (v1.GetLONG() == v2.GetLONG())
{
bMatch = TRUE;
}
}
else if (V_VT(&v1) == VT_BSTR && V_VT(&v2) == VT_BSTR)
{
if (wbem_wcsicmp(v1.GetStr(), v2.GetStr()) == 0)
{
bMatch = TRUE;
}
}
// If a match, spawn the association and bind it.
// ==============================================
if (bMatch)
{
IWbemClassObject *pAssocInst = 0;
if (FAILED(hRes = pAssocClass->SpawnInstance(0, &pAssocInst))) return hRes;
CReleaseMe rmAssoc(pAssocInst);
CVARIANT vPath1, vPath2;
if (FAILED(hRes = pObj1->Get(L"__RELPATH", 0, &vPath1, 0, 0))) return hRes;
if (FAILED(hRes = pObj2->Get(L"__RELPATH", 0, &vPath2, 0, 0))) return hRes;
if (FAILED(hRes = pAssocInst->Put(pszAssocRef1, 0, &vPath1, 0))) return hRes;
if (FAILED(hRes = pAssocInst->Put(pszAssocRef2, 0, &vPath2, 0))) return hRes;
wmilib::auto_ptr<SAssocTriad> pTriad( new SAssocTriad);
if (NULL == pTriad.get()) return WBEM_E_OUT_OF_MEMORY;
pTriad->m_pEp1 = pObj1;
pTriad->m_pEp1->AddRef();
pTriad->m_pEp2 = pObj2;
pTriad->m_pEp2->AddRef();
pTriad->m_pAssoc = pAssocInst;
pTriad->m_pAssoc->AddRef();
if (CFlexArray::no_error != aTriads.Add(pTriad.get())) return WBEM_E_OUT_OF_MEMORY;
pTriad.release();
}
}
}
return hRes;
}
//***************************************************************************
//
//***************************************************************************
//
HRESULT CWbemNamespace::ExtractEpInfoFromQuery(
IN IWbemQuery *pQuery,
wmilib::auto_buffer<WCHAR> & pszRetClass1,
wmilib::auto_buffer<WCHAR> & pszRetProp1,
wmilib::auto_buffer<WCHAR> & pszRetClass2,
wmilib::auto_buffer<WCHAR> & pszRetProp2
)
{
HRESULT hRes;
SWQLNode *pRoot;
hRes = pQuery->GetAnalysis(
WMIQ_ANALYSIS_RESERVED,
0,
(LPVOID *) &pRoot
);
if (FAILED(hRes))
return hRes;
// Move down the parse tree to find the JOIN clause.
// =================================================
if (!pRoot || pRoot->m_dwNodeType != TYPE_SWQLNode_QueryRoot)
return WBEM_E_INVALID_QUERY;
pRoot = pRoot->m_pLeft;
if (!pRoot || pRoot->m_dwNodeType != TYPE_SWQLNode_Select)
return WBEM_E_INVALID_QUERY;
pRoot = pRoot->m_pLeft;
if (!pRoot || pRoot->m_dwNodeType != TYPE_SWQLNode_TableRefs)
return WBEM_E_INVALID_QUERY;
pRoot = pRoot->m_pRight;
if (!pRoot || pRoot->m_dwNodeType != TYPE_SWQLNode_FromClause)
return WBEM_E_INVALID_QUERY;
pRoot = pRoot->m_pLeft;
if (!pRoot || pRoot->m_dwNodeType != TYPE_SWQLNode_Join)
return WBEM_E_INVALID_QUERY;
// We are now at the JOIN node.
// ============================
SWQLNode_Join *pJoin = (SWQLNode_Join *) pRoot;
/* The parse tree is left-heavy and looks like this:
JN Join node
/ \ / \
JP OC JoinPair OnClause
/ \ / \
TR TR TableRef TableRef
*/
// First, get the first table & prop.
// ==================================
SWQLNode_JoinPair *pPair = (SWQLNode_JoinPair *) pJoin->m_pLeft;
if (!pPair || pPair->m_dwNodeType != TYPE_SWQLNode_JoinPair)
return WBEM_E_INVALID_QUERY;
SWQLNode_TableRef *pT1 = (SWQLNode_TableRef *) pPair->m_pLeft;
SWQLNode_TableRef *pT2 = (SWQLNode_TableRef *) pPair->m_pRight;
if (!pT1 || !pT2)
return WBEM_E_INVALID_QUERY;
SWQLNode_OnClause *pOC = (SWQLNode_OnClause *) pJoin->m_pRight;
if (!pOC)
return WBEM_E_INVALID_QUERY;
SWQLNode_RelExpr *pRE = (SWQLNode_RelExpr *) pOC->m_pLeft;
if (!pRE)
return WBEM_E_INVALID_QUERY;
if (pRE->m_dwExprType != WQL_TOK_TYPED_EXPR)
return WBEM_E_INVALID_QUERY;
// We now have the table names available and the matching condition.
// ==================================================================
LPWSTR pszClass = pRE->m_pTypedExpr->m_pTableRef;
LPWSTR pszProp = pRE->m_pTypedExpr->m_pColRef;
LPWSTR pszClass2 = pRE->m_pTypedExpr->m_pJoinTableRef;
LPWSTR pszProp2 = pRE->m_pTypedExpr->m_pJoinColRef;
if (wbem_wcsicmp(pT1->m_pTableName, pszClass) != 0)
pszClass = pT1->m_pAlias;
if (wbem_wcsicmp(pT2->m_pTableName, pszClass2) != 0)
pszClass2 = pT2->m_pAlias;
if (pszClass == 0 || pszProp == 0 || pszClass2 == 0 || pszProp2 == 0)
return WBEM_E_INVALID_QUERY;
pszRetClass1.reset(Macro_CloneLPWSTR(pszClass));
if (NULL == pszRetClass1.get()) return WBEM_E_OUT_OF_MEMORY;
pszRetProp1.reset(Macro_CloneLPWSTR(pszProp));
if (NULL == pszRetProp1.get()) return WBEM_E_OUT_OF_MEMORY;
pszRetClass2.reset(Macro_CloneLPWSTR(pszClass2));
if (NULL == pszRetClass2.get()) return WBEM_E_OUT_OF_MEMORY;
pszRetProp2.reset(Macro_CloneLPWSTR(pszProp2));
if (NULL ==pszRetProp2.get()) return WBEM_E_OUT_OF_MEMORY;
return WBEM_S_NO_ERROR;
}
//***************************************************************************
//
// CWbemNamespace::BuildRuleBasedPathToInst
//
// Based on the incoming info, computes the path to the would-be other
// endpoint.
//
// <pEp> The known endpoint.
// <pszJoinProp1> The property in <pEp> which matches the property in the
// unknown EP.
// <pEp2> Class for the other endpoint.
// <pszJoinProp2> The property in the other class which matches the
// <pszJoinProp1> in the known endpoint class.
// <wsNewPath> The proposed path to the instance of class <pEp2>. Who
// knows whether or not we will find it, but we can try.
//
//***************************************************************************
//
HRESULT CWbemNamespace::BuildRuleBasedPathToInst(
IWbemClassObject *pEp,
LPWSTR pszJoinProp1,
IWbemClassObject *pEp2,
LPWSTR pszJoinProp2,
OUT WString &wsNewPath
)
{
HRESULT hRes;
// Get the property from the <pEp> which is the cause of all the fuss.
// ===================================================================
_variant_t vProp;
hRes = pEp->Get(pszJoinProp1, 0, &vProp, 0, 0);
if (FAILED(hRes))
return hRes;
_variant_t vClass2;
hRes = pEp2->Get(L"__CLASS", 0, &vClass2, 0, 0);
if (FAILED(hRes)) return hRes;
if (VT_BSTR != V_VT(&vClass2)) return WBEM_E_INVALID_PARAMETER;
wsNewPath = V_BSTR(&vClass2);
wsNewPath += L".";
wsNewPath += pszJoinProp2;
wsNewPath += L"=";
// Note 98: Doesn't work for compound keys!! Yuck.
// ===============================================
_variant_t vDest;
hRes = VariantChangeType(&vDest, &vProp, 0, VT_BSTR);
if (FAILED(hRes)) return hRes;
wsNewPath += V_BSTR(&vDest);
return hRes;
}
//***************************************************************************
//
// CWbemNamespace::ManufactureAssocs
//
// Manufactures the associations based on the rule in the <pszJoinQuery>
// which was extracted from the <rulebased> qualifier. Queries the two
// endpoint classes and joins the instances to produce the associations
//
// <pAssocClass> The association class definition which contains the rule.
// <pEp> Optional endpoint object. If not NULL, only objects
// which associate to this endpoint will be returned in
// the triad list, typically a single object.
// <pCtx> Call context
// <pszJoinQuery> The rule query text
// <aTriads> Receives the output, an array of SAssocTriad pointers.
// Caller must call SAssocTriad::ArrayCleanup.
//
//***************************************************************************
HRESULT CWbemNamespace::ManufactureAssocs(
IN IWbemClassObject *pAssocClass,
IN IWbemClassObject *pEp, // Optional
IN IWbemContext *pCtx,
IN LPWSTR pszJoinQuery,
OUT CFlexArray &aTriads
)
{
HRESULT hRes;
WString q1, q2;
CFlexArray aEp1List;
OnDelete<CFlexArray &,void(*)(CFlexArray &),EmptyObjectList> EmptyMe1(aEp1List);
CFlexArray aEp2List;
OnDelete<CFlexArray &,void(*)(CFlexArray &),EmptyObjectList> EmptyMe2(aEp2List);
wmilib::auto_buffer<WCHAR> pClassName1;
wmilib::auto_buffer<WCHAR> pClassName2;
wmilib::auto_buffer<WCHAR> pszJoinProp1;
wmilib::auto_buffer<WCHAR> pszJoinProp2;
wmilib::auto_buffer<WCHAR> pszAssocRef1;
wmilib::auto_buffer<WCHAR> pszAssocRef2;
_IWmiQuery *pQuery = 0;
// Parse the query.
// ================
CCoreServices *pSvc = CCoreServices::CreateInstance();
if (NULL == pSvc) return WBEM_E_OUT_OF_MEMORY;
CReleaseMe rmSvc(pSvc);
hRes = pSvc->CreateQueryParser(0, &pQuery);
if (FAILED(hRes)) return hRes;
CReleaseMe rmQuery(pQuery);
hRes = pQuery->Parse(L"SQL", pszJoinQuery, 0);
if (FAILED(hRes)) return hRes;
// Extract the endpoint class names.
// ==================================
hRes = ExtractEpInfoFromQuery(pQuery, pClassName1,pszJoinProp1, pClassName2, pszJoinProp2);
if (FAILED(hRes)) return hRes;
// Get the endpoint class defs.
// ============================
IWbemClassObject *pClsDef1 = 0;
hRes = InternalGetClass(pClassName1.get(), &pClsDef1);
if (FAILED(hRes)) return hRes;
CReleaseMe rmCls1(pClsDef1);
IWbemClassObject *pClsDef2 = 0;
hRes = InternalGetClass(pClassName2.get(), &pClsDef2);
if (FAILED(hRes)) return hRes;
CReleaseMe rmCls2(pClsDef2);
// Map which assoc ref properties point to which class.
// ====================================================
hRes = MapAssocRefsToClasses(pAssocClass, pClsDef1, pClsDef2, pszAssocRef1, pszAssocRef2);
if (FAILED(hRes)) return hRes;
// If no specific endpoint, an enumeration is requested. We query the endpoint
// classes completely and match everything up.
// ============================================================================
IWbemClassObject *pEp2 = 0;
CReleaseMeRef<IWbemClassObject *> rmRefEp2(pEp2);
if (pEp == 0)
{
// Build the queries.
// ===================
q1 = "select * from ";
q1 += pClassName1.get();
q2 = "select * from ";
q2 += pClassName2.get();
hRes = ExecSyncQuery(q1, pCtx, 0, aEp1List);
if (FAILED(hRes)) return hRes;
hRes = ExecSyncQuery(q2, pCtx, 0, aEp2List);
if (FAILED(hRes)) return hRes;
}
else
{
// Note 99: Oversimplified in that it doesn't do an enum; assumes a 1:1 mapping.
// Compute the path to the other endpoint based on the rule.
// =============================================================================
WString wsNewPath;
hRes = BuildRuleBasedPathToInst(pEp, pszJoinProp1.get(), pClsDef2, pszJoinProp2.get(), wsNewPath); // throws
if (FAILED(hRes)) return hRes;
// Do a get object.
// ================
hRes = InternalGetInstance(wsNewPath, &pEp2);
if (FAILED(hRes)) return hRes;
if (CFlexArray::no_error != aEp1List.Add(pEp)) return WBEM_E_OUT_OF_MEMORY;
pEp->AddRef();
if (CFlexArray::no_error != aEp2List.Add(pEp2)) return WBEM_E_OUT_OF_MEMORY;
pEp2->AddRef();
}
// Now, match up the results.
// For single-object type scenarios, the arrays simply have one element in them. Ho hum.
// =====================================================================================
OnDeleteIf<CFlexArray &,void(*)(CFlexArray &),EmptyObjectList> EmptyMeTriads(aTriads);
hRes = BuildAssocTriads(
pAssocClass,
pClsDef1,
pClsDef2,
pszJoinProp1.get(),
pszJoinProp2.get(),
pszAssocRef1.get(),
pszAssocRef2.get(),
aEp1List,
aEp2List,
aTriads // OUT
);
if (FAILED(hRes)) return hRes;
EmptyMeTriads.dismiss();
return hRes;
}
//***************************************************************************
//
// CWbemNamespace::GetAceList
//
// Retrieves the ACEs associated with this namespace
//
// <ppAceList> Flexarray to hold ACE list
//
//***************************************************************************
HRESULT CWbemNamespace::GetAceList(CFlexAceArray** ppAceList)
{
HRESULT hRes=S_OK;
*ppAceList = new CFlexAceArray;
if (ppAceList==NULL)
hRes = WBEM_E_OUT_OF_MEMORY;
else
{
// 1. Get security descriptor
CNtSecurityDescriptor& sd = GetSDRef();
// 2. Get the DACL
CNtAcl* pDacl;
pDacl = sd.GetDacl();
if ( pDacl==NULL )
return WBEM_E_OUT_OF_MEMORY;
CDeleteMe<CNtAcl> dm(pDacl);
// 3. Loop through DACL
int iNumAces = pDacl->GetNumAces();
for ( int i=0; i<iNumAces; i++ )
{
CNtAce* Ace;
Ace = pDacl->GetAce(i);
if ( Ace == NULL )
return WBEM_E_OUT_OF_MEMORY;
(*ppAceList)->Add (Ace);
}
}
return hRes;
}
//***************************************************************************
//
// CWbemNamespace::PutAceList
//
// Puts the ACEs associated with this namespace
//
// <ppAceList> Flexarray ACE list
//
//***************************************************************************
HRESULT CWbemNamespace::PutAceList(CFlexAceArray* pFlex)
{
SCODE sc = S_OK;
CNtAcl DestAcl;
int iNumAces = pFlex->Size();
for (int i=0; i<iNumAces; i++ )
{
if ( DestAcl.AddAce ((CNtAce*) pFlex->GetAt(i)) == FALSE )
{
return WBEM_E_INVALID_OBJECT;
}
}
if ( m_sd.SetDacl (&DestAcl) == FALSE )
return WBEM_E_INVALID_OBJECT;
sc = StoreSDIntoNamespace(m_pSession, m_pNsHandle, m_sd);
if ( !FAILED (sc) )
sc = RecursiveSDMerge();
return sc;
}
//***************************************************************************
//
// CWbemNamespace::GetDynamicReferenceClasses
//
// Asks the provider subsystem for dynamic association classes.
//
//
//***************************************************************************
HRESULT CWbemNamespace::GetDynamicReferenceClasses( long lFlags, IWbemContext
* pCtx, IWbemObjectSink* pSink )
{
HRESULT hRes = WBEM_S_NO_ERROR;
_IWmiProviderAssociatorsHelper* pAssocHelp = NULL;
if ( m_pProvFact)
{
hRes = m_pProvFact->GetClassProvider(
0, // lFlags
pCtx,
m_wszUserName,
m_wsLocale,
m_pThisNamespace,
0,
IID__IWmiProviderAssociatorsHelper,
(LPVOID *) &pAssocHelp
);
CReleaseMe rm( pAssocHelp );
if ( SUCCEEDED( hRes ) )
{
hRes = pAssocHelp->GetReferencesClasses( lFlags, pCtx, pSink );
}
if ( FAILED( hRes ) )
{
pSink->SetStatus( 0L, hRes, 0L, 0L );
}
}
else
{
pSink->SetStatus( 0L, WBEM_S_NO_ERROR, 0L, 0L );
}
return hRes;
}