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.
4411 lines
139 KiB
4411 lines
139 KiB
//***************************************************************************
|
|
//
|
|
// Copyright © Microsoft Corporation. All rights reserved.
|
|
//
|
|
// WBEMGLUE.CPP
|
|
//
|
|
// Purpose: Implementation of CWbemProviderGlue class
|
|
//
|
|
//***************************************************************************
|
|
|
|
#include "precomp.h"
|
|
#include <assertbreak.h>
|
|
#include <eventProvider.h>
|
|
#include <FRQueryEx.h>
|
|
#include <cnvmacros.h>
|
|
#include <BrodCast.h>
|
|
#include <cominit.h>
|
|
#include <StopWatch.h>
|
|
#include <comdef.h>
|
|
#include <SmartPtr.h>
|
|
#include <lmcons.h>
|
|
#define SECURITY_WIN32
|
|
#include <sspi.h>
|
|
#include <Secext.h>
|
|
#include "FWStrings.h"
|
|
#include "MultiPlat.h"
|
|
#include <AutoImpRevert.h>
|
|
#include <lockwrap.h>
|
|
|
|
#include <winbasep.h>
|
|
|
|
#include <helper.h>
|
|
|
|
typedef FrameDynOnDelete < CRITICAL_SECTION *, VOID ( * ) ( LPCRITICAL_SECTION ), LeaveCriticalSection > LeaveCriticalSectionScope;
|
|
typedef WaitException < CRITICAL_SECTION *, VOID ( * ) ( LPCRITICAL_SECTION ), EnterCriticalSection, 1000 > EnterCriticalSectionWait;
|
|
|
|
|
|
class CWbemGlueImpersonation
|
|
{
|
|
CWbemGlueImpersonation ( const CWbemGlueImpersonation& ) {}
|
|
|
|
HRESULT m_hr;
|
|
|
|
public:
|
|
|
|
CWbemGlueImpersonation () : m_hr ( E_FAIL )
|
|
{
|
|
m_hr = CWbemProviderGlue::CheckImpersonationLevel ();
|
|
}
|
|
|
|
~CWbemGlueImpersonation ()
|
|
{
|
|
if SUCCEEDED ( m_hr )
|
|
{
|
|
WbemCoRevertToSelf ();
|
|
}
|
|
}
|
|
|
|
HRESULT IsImpersonated () const
|
|
{
|
|
return m_hr;
|
|
}
|
|
};
|
|
|
|
#define GLUETIMEOUT WBEM_INFINITE //(3 * 60 * 1000)
|
|
|
|
// Used in ASSERT_BREAK to give meaningful messages
|
|
#define DEPRECATED 1
|
|
#define MEMORY_EXHAUSTED 0
|
|
#define FRAMEWORK_EXCEPTION 0
|
|
#define UNSPECIFIED_EXCEPTION 0
|
|
#define STRUCTURED_EXCEPTION 0
|
|
#define DUPLICATE_RELEASE 0
|
|
#define IMPERSONATION_REVERTED 0
|
|
#define UNNECESSARY_CWBEMPROVIDERGLUE_INSTANCE 0
|
|
|
|
// Initialize Statics
|
|
STRING2LPVOID CWbemProviderGlue::s_providersmap;
|
|
CCritSec CWbemProviderGlue::s_csFactoryMap;
|
|
PTR2PLONG CWbemProviderGlue::s_factorymap;
|
|
CCritSec CWbemProviderGlue::s_csProviderMap;
|
|
CCritSec CWbemProviderGlue::m_csStatusObject;
|
|
IWbemClassObject *CWbemProviderGlue::m_pStatusObject = NULL;
|
|
BOOL CWbemProviderGlue::s_bInitted = FALSE;
|
|
DWORD CWbemProviderGlue::s_dwPlatform = 0;
|
|
DWORD CWbemProviderGlue::s_dwMajorVersion = 0;
|
|
WCHAR CWbemProviderGlue::s_wstrCSDVersion[_MAX_PATH] = {0};
|
|
|
|
long CWbemProviderGlue::s_lObjects = 0;
|
|
|
|
// Static Provider we use to initialize, uninitialize our static
|
|
// data. We should be able to assume at Construct/Destruct time that
|
|
// we (the DLL) are being loaded/unloaded.
|
|
// later on -- we should, but we can't. Current model is that we
|
|
// uninitialize when the last DLL that we service has called DLLLogoff,
|
|
// which had better be in response to "DllCanUnloadNow"
|
|
|
|
CWbemProviderGlue g_wbemprovider;
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::CWbemProviderGlue
|
|
//
|
|
// Class CTor. Uses static initialization functon to get static data
|
|
// ready if this is the first instance of our object.
|
|
//
|
|
// Inputs: None
|
|
//
|
|
// Outputs: None.
|
|
//
|
|
// Returns: None.
|
|
//
|
|
// Comments:
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
CWbemProviderGlue::CWbemProviderGlue()
|
|
: m_strNamespace(),
|
|
m_lRefCount(0),
|
|
m_pCount(NULL),
|
|
m_pServices(NULL)
|
|
{
|
|
Init();
|
|
}
|
|
|
|
CWbemProviderGlue::CWbemProviderGlue(PLONG pCount)
|
|
: m_strNamespace(),
|
|
m_lRefCount(0),
|
|
m_pCount(pCount),
|
|
m_pServices(NULL)
|
|
{
|
|
CWbemProviderGlue::IncrementMapCount(pCount);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::~CWbemProviderGlue
|
|
//
|
|
// Class DTor.
|
|
//
|
|
// Inputs: None
|
|
//
|
|
// Outputs: None.
|
|
//
|
|
// Returns: None.
|
|
//
|
|
// Comments:
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
CWbemProviderGlue::~CWbemProviderGlue()
|
|
{
|
|
// Note that the item we are destructing here was not added in
|
|
// the constructor, but in Initialize().
|
|
if (m_pServices)
|
|
{
|
|
m_pServices->Release();
|
|
}
|
|
|
|
if (m_pCount != NULL) // Indicates the static instance
|
|
{
|
|
if (DecrementMapCount(m_pCount) == 0)
|
|
{
|
|
FlushAll();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UnInit();
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::Init
|
|
//
|
|
// Static initialization function for initializing critical sections
|
|
// and such for making our static data thread-safe.
|
|
//
|
|
// Inputs: None.
|
|
//
|
|
// Outputs: None.
|
|
//
|
|
// Returns: None.
|
|
//
|
|
// Comments: Because we are protecting static data, we are using
|
|
// a named mutex. Construction and Destruction of object
|
|
// instances should call these functions.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
void CWbemProviderGlue::Init( void )
|
|
{
|
|
LogMessage(IDS_GLUEINIT);
|
|
|
|
if (!s_bInitted)
|
|
{
|
|
// Note that we *have* to use the ansi version at this point,
|
|
// since this is where we decide whether to use the ansi functions
|
|
// or the unicode ones.
|
|
OSVERSIONINFOA OsVersionInfoA;
|
|
|
|
OsVersionInfoA.dwOSVersionInfoSize = sizeof (OSVERSIONINFOA) ;
|
|
GetVersionExA(&OsVersionInfoA);
|
|
|
|
s_dwPlatform = OsVersionInfoA.dwPlatformId;
|
|
s_dwMajorVersion = OsVersionInfoA.dwMajorVersion;
|
|
|
|
if (OsVersionInfoA.szCSDVersion == NULL)
|
|
{
|
|
s_wstrCSDVersion[0] = L'\0';
|
|
}
|
|
else
|
|
{
|
|
bool t_ConversionFailure = false ;
|
|
WCHAR *wcsBuffer = NULL ;
|
|
ANSISTRINGTOWCS(OsVersionInfoA.szCSDVersion, wcsBuffer, t_ConversionFailure );
|
|
if ( ! t_ConversionFailure )
|
|
{
|
|
if ( wcsBuffer )
|
|
{
|
|
StringCchCopyW(s_wstrCSDVersion, _MAX_PATH, wcsBuffer);
|
|
}
|
|
else
|
|
{
|
|
throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Should do something here since we know version is not initialised.
|
|
}
|
|
}
|
|
|
|
s_bInitted = TRUE;
|
|
}
|
|
else
|
|
{
|
|
ASSERT_BREAK(UNNECESSARY_CWBEMPROVIDERGLUE_INSTANCE);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::UnInit
|
|
//
|
|
// Static cleanup function for cleaning up critical sections
|
|
// and such for making our static data thread-safe.
|
|
//
|
|
// Inputs: None.
|
|
//
|
|
// Outputs: None.
|
|
//
|
|
// Returns: None.
|
|
//
|
|
// Comments: Because we are protecting static data, we are using
|
|
// a named mutex. Construction and Destruction of object
|
|
// instances should call these functions.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
void CWbemProviderGlue::UnInit( void )
|
|
{
|
|
try
|
|
{
|
|
LogMessage(IDS_GLUEUNINIT);
|
|
}
|
|
catch ( ... )
|
|
{
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::GetStaticMutex
|
|
//
|
|
// Creates and returns an instance of the named mutex used to
|
|
// protect our static initialization functions.
|
|
//
|
|
// Inputs: None.
|
|
//
|
|
// Outputs: None.
|
|
//
|
|
// Returns: None.
|
|
//
|
|
// Comments: The mutex, although it is named, makes the process
|
|
// id part of the name, guaranteeing that it is still
|
|
// unique across processes.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::QueryInterface
|
|
//
|
|
// COM function called to ask us if we support a particular
|
|
// face type. If so, we addref ourselves and return the
|
|
// ourselves as an LPVOID.
|
|
//
|
|
// Inputs: REFIID riid - Interface being queried for.
|
|
//
|
|
// Outputs: LPVOID FAR* ppvObj - Interface pointer.
|
|
//
|
|
// Returns: None.
|
|
//
|
|
// Comments: The only interfaces we support are IID_IUnknown and
|
|
// IID_IWbemServices.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
STDMETHODIMP CWbemProviderGlue::QueryInterface( REFIID riid, LPVOID FAR *ppvObj )
|
|
{
|
|
LogMessage(L"CWbemProviderGlue::QueryInterface");
|
|
|
|
if (IsEqualIID(riid, IID_IUnknown))
|
|
{
|
|
*ppvObj = (IWbemServices *) this;
|
|
}
|
|
else if (IsEqualIID(riid, IID_IWbemServices))
|
|
{
|
|
*ppvObj = (IWbemServices *) this;
|
|
}
|
|
else if (IsEqualIID(riid, IID_IWbemProviderInit))
|
|
{
|
|
*ppvObj = (IWbemProviderInit *) this;
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
*ppvObj = NULL ;
|
|
if (IsVerboseLoggingEnabled())
|
|
{
|
|
WCHAR wcID[128];
|
|
StringFromGUID2(riid, wcID, 128);
|
|
|
|
LogMessage2(L"CWbemProviderGlue::QueryInterface - unsupported interface (%s)", wcID);
|
|
}
|
|
}
|
|
catch ( ... )
|
|
{
|
|
}
|
|
|
|
return ResultFromScode(E_NOINTERFACE) ;
|
|
}
|
|
|
|
AddRef() ;
|
|
|
|
return NOERROR ;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::AddRef
|
|
//
|
|
// Increments the reference count on this object.
|
|
//
|
|
// Inputs: None.
|
|
//
|
|
// Outputs: None.
|
|
//
|
|
// Returns: ULONG - Our Reference Count.
|
|
//
|
|
// Comments: Requires that a correponding call to Release be
|
|
// performed.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
ULONG CWbemProviderGlue::AddRef( void )
|
|
{
|
|
CSetStructuredExceptionHandler t_ExceptionHandler;
|
|
|
|
try
|
|
{
|
|
if (IsVerboseLoggingEnabled())
|
|
{
|
|
// this will be an approximation because another thread could come through...
|
|
LogMessage2(L"CWbemProviderGlue::AddRef, count is (approx) %d", m_lRefCount +1);
|
|
};
|
|
}
|
|
catch ( ... )
|
|
{
|
|
}
|
|
|
|
// InterlockedIncrement does not necessarily return the
|
|
// correct value, only whether the value is <, =, > 0.
|
|
// However it is guaranteed threadsafe.
|
|
|
|
return InterlockedIncrement( &m_lRefCount );
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::Intialize
|
|
//
|
|
// Inputs: Many.
|
|
//
|
|
// Outputs: None.
|
|
//
|
|
// Returns:
|
|
//
|
|
// Comments: any global initializations, esp those that call CIMOM should go here.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
HRESULT CWbemProviderGlue::Initialize(
|
|
/* [in] */ LPWSTR pszUser,
|
|
/* [in] */ LONG lFlags,
|
|
/* [in] */ LPWSTR pszNamespace,
|
|
/* [in] */ LPWSTR pszLocale,
|
|
/* [in] */ IWbemServices __RPC_FAR *pNamespace,
|
|
/* [in] */ IWbemContext __RPC_FAR *pCtx,
|
|
/* [in] */ IWbemProviderInitSink __RPC_FAR *pInitSink)
|
|
{
|
|
CSetStructuredExceptionHandler t_ExceptionHandler;
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
|
|
try
|
|
{
|
|
if (IsVerboseLoggingEnabled())
|
|
{
|
|
LogMessage3(L"%s(%s)", IDS_GLUEINITINTERFACE, pszNamespace);
|
|
}
|
|
}
|
|
catch ( ... )
|
|
{
|
|
}
|
|
|
|
if ( (NULL != pszNamespace) && (NULL != pNamespace) )
|
|
{
|
|
try
|
|
{
|
|
// this may come back to bite me
|
|
// CIMOM promises that this will only be called on one thread, once per object
|
|
// and that no queries will be issued until after initialize is called.
|
|
// therefore - I don't need a critical section, here -
|
|
m_strNamespace = pszNamespace;
|
|
m_strNamespace.MakeUpper();
|
|
|
|
pNamespace->AddRef();
|
|
m_pServices = pNamespace;
|
|
}
|
|
catch ( CFramework_Exception e_FR )
|
|
{
|
|
ASSERT_BREAK(FRAMEWORK_EXCEPTION);
|
|
hr = WBEM_E_PROVIDER_FAILURE;
|
|
}
|
|
catch ( CHeap_Exception e_HE )
|
|
{
|
|
ASSERT_BREAK(MEMORY_EXHAUSTED);
|
|
hr = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
catch(CStructured_Exception e_SE)
|
|
{
|
|
ASSERT_BREAK(STRUCTURED_EXCEPTION);
|
|
hr = WBEM_E_PROVIDER_FAILURE;
|
|
}
|
|
catch ( ... )
|
|
{
|
|
ASSERT_BREAK(UNSPECIFIED_EXCEPTION);
|
|
hr = WBEM_E_PROVIDER_FAILURE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = WBEM_E_FAILED;
|
|
}
|
|
|
|
if (pInitSink)
|
|
{
|
|
pInitSink->SetStatus(hr, 0);
|
|
hr = WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::Release
|
|
//
|
|
// Decrements the reference count on this object.
|
|
//
|
|
// Inputs: None.
|
|
//
|
|
// Outputs: None.
|
|
//
|
|
// Returns: ULONG - Our Reference Count.
|
|
//
|
|
// Comments: When the ref count hits zero, the object is deleted.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
ULONG CWbemProviderGlue::Release()
|
|
{
|
|
// InterlockedDecrement does not necessarily return the
|
|
// correct value, only whether the value is <, =, > 0.
|
|
// However it is guaranteed threadsafe.
|
|
|
|
// We want to hold the value locally in case two threads
|
|
// Release at the same time and one gets a final release,
|
|
// and deletes, leaving a potential window in which a thread
|
|
// deletes the object before the other returns and tries to
|
|
// reference the value from within the deleted object.
|
|
|
|
CSetStructuredExceptionHandler t_ExceptionHandler;
|
|
ULONG nRet = InterlockedDecrement( &m_lRefCount );
|
|
|
|
try
|
|
{
|
|
if (IsVerboseLoggingEnabled())
|
|
{
|
|
LogMessage2(L"CWbemProviderGlue::Release, count is (approx) %d", m_lRefCount);
|
|
}
|
|
}
|
|
catch ( ... )
|
|
{
|
|
}
|
|
|
|
if( 0 == nRet )
|
|
{
|
|
try
|
|
{
|
|
LogMessage(IDS_GLUEREFCOUNTZERO);
|
|
}
|
|
catch ( ... )
|
|
{
|
|
}
|
|
delete this;
|
|
} else if (nRet > 0x80000000)
|
|
{
|
|
ASSERT_BREAK(DUPLICATE_RELEASE);
|
|
}
|
|
|
|
return nRet;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::FlushAll
|
|
//
|
|
// Inputs: voidness
|
|
//
|
|
// Outputs: more voidness
|
|
//
|
|
// Returns: see above
|
|
//
|
|
// Comments: flushes caches, calls all of the provider's flushes.
|
|
// no need to flush event providers map, flush will be
|
|
// called on the provider pointer
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
void CWbemProviderGlue::FlushAll(void)
|
|
{
|
|
PROVIDERPTRS::iterator setIter;
|
|
|
|
// We DEFINITELY want to protect the Map while this is running!
|
|
EnterCriticalSectionWait ecs ( &s_csProviderMap );
|
|
LeaveCriticalSectionScope lcs ( &s_csProviderMap );
|
|
|
|
try
|
|
{
|
|
// pProvider doesn't get addref'ed, so doesn't need to be released
|
|
Provider *pProvider = NULL;
|
|
|
|
EnterCriticalSectionWait ecs1 ( &m_csFlushPtrs );
|
|
LeaveCriticalSectionScope lcs1 ( &m_csFlushPtrs );
|
|
|
|
for (setIter = m_FlushPtrs.begin(); setIter != m_FlushPtrs.end(); setIter++)
|
|
{
|
|
pProvider = (Provider*) *setIter;
|
|
if ( pProvider != NULL )
|
|
{
|
|
// If one provider poops out, try the others.
|
|
try
|
|
{
|
|
pProvider->Flush();
|
|
}
|
|
catch ( ... )
|
|
{
|
|
}
|
|
}
|
|
}
|
|
|
|
m_FlushPtrs.clear();
|
|
}
|
|
catch ( ... )
|
|
{
|
|
// we should not be here
|
|
// do not re-throw (called from destructor)
|
|
}
|
|
|
|
lcs.Exec ();
|
|
|
|
if (m_pStatusObject)
|
|
{
|
|
EnterCriticalSectionWait ecs1 ( &m_csStatusObject );
|
|
LeaveCriticalSectionScope lcs1 ( &m_csStatusObject );
|
|
|
|
if (m_pStatusObject)
|
|
{
|
|
m_pStatusObject->Release();
|
|
m_pStatusObject = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
// SetStatusObject
|
|
// sets the properties in the extended status object so that it can be returned when
|
|
// the glue layer calls SetStatus at the end of the method invocation.
|
|
// will return false if the status object has already been filled.
|
|
// (first one in wins)
|
|
bool CWbemProviderGlue::SetStatusObject(
|
|
|
|
MethodContext *pContext,
|
|
LPCWSTR pNamespace,
|
|
LPCWSTR pDescription,
|
|
HRESULT hr,
|
|
const SAFEARRAY *pPrivilegesNotHeld,/* = NULL */
|
|
const SAFEARRAY *pPrivilegesRequired/* = NULL */
|
|
)
|
|
{
|
|
bool bRet = false;
|
|
|
|
ASSERT_BREAK(pContext != NULL);
|
|
if (pContext)
|
|
{
|
|
IWbemClassObjectPtr pObj ( GetStatusObject(pContext, pNamespace), false );
|
|
|
|
if (pObj != NULL)
|
|
{
|
|
// Variant_t handles the VariantInit/VariantClear
|
|
variant_t v;
|
|
|
|
pContext->SetStatusObject(pObj);
|
|
|
|
// set hresult ("StatusCode")
|
|
v.vt = VT_I4;
|
|
v.lVal = (long)hr;
|
|
pObj->Put(IDS_STATUSCODE, 0, &v, NULL);
|
|
v.Clear();
|
|
|
|
// set description
|
|
if (pDescription)
|
|
{
|
|
v = pDescription;
|
|
|
|
if (v.bstrVal != NULL)
|
|
{
|
|
bRet = SUCCEEDED(pObj->Put(IDS_DESCRIPTION, 0, &v, NULL));
|
|
}
|
|
else
|
|
{
|
|
throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
|
|
}
|
|
|
|
v.Clear();
|
|
}
|
|
|
|
// privileges properties
|
|
if (pPrivilegesNotHeld)
|
|
{
|
|
SAFEARRAY *pSafeArray = NULL;
|
|
// blithy casting away the const...
|
|
if ( SUCCEEDED ( SafeArrayCopy ((SAFEARRAY*)pPrivilegesNotHeld, &pSafeArray ) ) )
|
|
{
|
|
v.vt = VT_BSTR | VT_ARRAY;
|
|
v.parray = pSafeArray;
|
|
pObj->Put(IDS_PRIVILEGESNOTHELD, 0, &v, NULL);
|
|
v.Clear();
|
|
}
|
|
else
|
|
{
|
|
throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
|
|
}
|
|
}
|
|
|
|
if (pPrivilegesRequired)
|
|
{
|
|
SAFEARRAY *pSafeArray = NULL;
|
|
// blithy casting away the const...
|
|
if ( SUCCEEDED ( SafeArrayCopy ((SAFEARRAY*)pPrivilegesRequired, &pSafeArray ) ) )
|
|
{
|
|
v.vt = VT_BSTR | VT_ARRAY;
|
|
v.parray = pSafeArray;
|
|
pObj->Put(IDS_PRIVILEGESREQUIRED, 0, &v, NULL);
|
|
v.Clear();
|
|
}
|
|
else
|
|
{
|
|
throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
IWbemClassObject *CWbemProviderGlue::GetStatusObject(
|
|
|
|
MethodContext *pContext,
|
|
LPCWSTR pNamespace
|
|
)
|
|
{
|
|
ASSERT_BREAK(pContext != NULL);
|
|
IWbemClassObject *pStatusObj = NULL;
|
|
|
|
if (pContext != NULL)
|
|
{
|
|
// first time in, we cache the class object
|
|
if (!m_pStatusObject)
|
|
{
|
|
m_csStatusObject.Enter();
|
|
|
|
// check again - someone might have snuck in!
|
|
if (!m_pStatusObject)
|
|
{
|
|
IWbemServicesPtr pSrvc;
|
|
IWbemContextPtr pWbemContext (pContext->GetIWBEMContext(), false);
|
|
|
|
pSrvc.Attach ( GetNamespaceConnection( pNamespace, pContext ) ) ;
|
|
if ( pSrvc )
|
|
{
|
|
// not checking return code, error object should be NULL on error
|
|
pSrvc->GetObject( bstr_t( IDS_WIN32PRIVILEGESSTATUS ), 0, pWbemContext, &m_pStatusObject, NULL );
|
|
}
|
|
|
|
}
|
|
m_csStatusObject.Leave();
|
|
}
|
|
|
|
if (m_pStatusObject)
|
|
m_pStatusObject->SpawnInstance(0, &pStatusObj);
|
|
}
|
|
else
|
|
{
|
|
LogErrorMessage(L"NULL parameter to GetStatusObject");
|
|
}
|
|
|
|
return pStatusObj;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::ExecQueryAsync
|
|
//
|
|
// Place holder for the ExecQuery function.
|
|
//
|
|
// Inputs: const BSTR QueryFormat - Query Format String
|
|
// const BSTR Query - The actual query
|
|
// long lFlags - Additional flags.
|
|
// IWbemContext __RPC_FAR *pCtx - Context we were called in.
|
|
// IWbemObjectSink FAR *pResponseHandler - Response Handler
|
|
//
|
|
// Outputs: None.
|
|
//
|
|
// Returns: ULONG - Our Reference Count.
|
|
//
|
|
// Comments:
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT CWbemProviderGlue::ExecQueryAsync(
|
|
|
|
const BSTR QueryFormat,
|
|
const BSTR Query,
|
|
long lFlags,
|
|
IWbemContext __RPC_FAR *pCtx,
|
|
IWbemObjectSink FAR *pResponseHandler
|
|
)
|
|
{
|
|
// make sure we don't disappear while running
|
|
AddRef();
|
|
|
|
CSetStructuredExceptionHandler t_ExceptionHandler;
|
|
|
|
#ifdef PROVIDER_INSTRUMENTATION
|
|
StopWatch stopWatch(CHString(IDS_EXECQUERY) + CHString(Query));
|
|
stopWatch.Start(StopWatch::FrameworkTimer);
|
|
#endif
|
|
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
IWbemClassObjectPtr pStatusObject;
|
|
|
|
try
|
|
{
|
|
if (IsVerboseLoggingEnabled())
|
|
{
|
|
LogMessage3(L"%s%s", IDS_EXECQUERY, Query);
|
|
}
|
|
|
|
// Now create an External Method Context object and go to town
|
|
ExternalMethodContextPtr pContext (new ExternalMethodContext( pResponseHandler, pCtx, this ), false);
|
|
|
|
#ifdef PROVIDER_INSTRUMENTATION
|
|
pContext->pStopWatch = &stopWatch;
|
|
#endif
|
|
|
|
if (pContext != NULL)
|
|
{
|
|
CFrameworkQueryEx CQuery;
|
|
// hr = CQuery.InitEx(QueryFormat, Query, lFlags, m_strNamespace);
|
|
hr = CQuery.Init(QueryFormat, Query, lFlags, m_strNamespace);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Find the class name for the query
|
|
bstr_t bstrClass (CQuery.GetQueryClassName(), false);
|
|
if ((WCHAR *)bstrClass != NULL)
|
|
{
|
|
// Search for the class name in our map of providers, we know which
|
|
// namespace we are when we get constructed.
|
|
// pProvider doesn't get addref'ed, so doesn't need to be released.
|
|
Provider *pProvider = SearchMapForProvider( bstrClass, m_strNamespace );
|
|
if ( NULL != pProvider )
|
|
{
|
|
|
|
// Initialize the CQuery.m_keysonly variable. Note that we CAN'T do this as part
|
|
// of Init, because we need the pProvider pointer. And we can do the init
|
|
// down here, because we need the bstrClass that we get from Init. And we can't
|
|
// do this as part of CQuery.KeysOnly because you can't get the IWbemClassObject
|
|
// from there.
|
|
IWbemClassObjectPtr IClass(pProvider->GetClassObjectInterface(pContext), false);
|
|
if (IClass != NULL)
|
|
{
|
|
CQuery.Init2(IClass);
|
|
|
|
// Impersonate connected user
|
|
CWbemGlueImpersonation impersonate;
|
|
if SUCCEEDED ( hr = impersonate.IsImpersonated () )
|
|
{
|
|
// Set up to call FlushAll
|
|
AddFlushPtr(pProvider);
|
|
|
|
WCHAR wszName[UNLEN + DNLEN + 1 + 1] = {0};
|
|
WCHAR wszName2[UNLEN + DNLEN + 1 + 1] = {0}; // domain + \ + name + null
|
|
DWORD dwLen = UNLEN + DNLEN + 1 + 1;
|
|
|
|
GetUserNameEx(NameSamCompatible, wszName, &dwLen);
|
|
|
|
// Everything is in place, run the query
|
|
hr = pProvider->ExecuteQuery( pContext, CQuery, lFlags );
|
|
|
|
dwLen = UNLEN + DNLEN + 1 + 1;
|
|
|
|
GetUserNameEx(NameSamCompatible, wszName2, &dwLen);
|
|
|
|
if (wcscmp(wszName, wszName2) != 0)
|
|
{
|
|
ASSERT_BREAK(IMPERSONATION_REVERTED);
|
|
LogErrorMessage4(L"Warning! User name at exit (%s) != user name at entry (%s) for %s",
|
|
wszName2, wszName, Query);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// we don't know WHY we couldn't get the interface,
|
|
// generic error it is...
|
|
hr = WBEM_E_FAILED;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
LogErrorMessage4(L"%s (%s:%s)", IDS_PROVIDERNOTFOUND, (LPCWSTR)m_strNamespace, (LPCWSTR)bstrClass);
|
|
hr = WBEM_E_INVALID_CLASS;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LogErrorMessage(IDS_INVALIDCLASSNAME);
|
|
hr = WBEM_E_INVALID_CLASS;
|
|
}
|
|
}
|
|
|
|
pStatusObject.Attach(pContext->GetStatusObject());
|
|
}
|
|
else
|
|
{
|
|
throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
|
|
}
|
|
|
|
if (IsVerboseLoggingEnabled())
|
|
{
|
|
if (SUCCEEDED(hr))
|
|
LogMessage3(L"%s%s - Succeeded", IDS_EXECQUERY, Query);
|
|
else
|
|
LogMessage4(L"%s%s - FAILED (%x)", IDS_EXECQUERY, Query, hr);
|
|
}
|
|
}
|
|
catch ( CFramework_Exception e_FR )
|
|
{
|
|
ASSERT_BREAK(FRAMEWORK_EXCEPTION);
|
|
hr = WBEM_E_PROVIDER_FAILURE;
|
|
}
|
|
catch ( CHeap_Exception e_HE )
|
|
{
|
|
ASSERT_BREAK(MEMORY_EXHAUSTED);
|
|
hr = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
catch(CStructured_Exception e_SE)
|
|
{
|
|
ASSERT_BREAK(STRUCTURED_EXCEPTION);
|
|
hr = WBEM_E_PROVIDER_FAILURE;
|
|
}
|
|
catch ( ... )
|
|
{
|
|
ASSERT_BREAK(UNSPECIFIED_EXCEPTION);
|
|
hr = WBEM_E_PROVIDER_FAILURE;
|
|
}
|
|
|
|
// We must call SetStatus so CIMOM doesn't lose any threads.
|
|
if ((hr != WBEM_E_INVALID_CLASS) && (hr != WBEM_E_UNSUPPORTED_PARAMETER))
|
|
{
|
|
#ifdef PROVIDER_INSTRUMENTATION
|
|
stopWatch.Start(StopWatch::WinMgmtTimer);
|
|
#endif
|
|
pResponseHandler->SetStatus( 0, hr, NULL, pStatusObject);
|
|
#ifdef PROVIDER_INSTRUMENTATION
|
|
stopWatch.Start(StopWatch::FrameworkTimer);
|
|
#endif
|
|
hr = WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
Release();
|
|
|
|
#ifdef PROVIDER_INSTRUMENTATION
|
|
stopWatch.Stop();
|
|
stopWatch.LogResults();
|
|
#endif
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::CreateInstanceEnumAsync
|
|
//
|
|
// Locates the provider for the specified class name and
|
|
// calls its CreateInstanceEnum function.
|
|
//
|
|
// Inputs: const BSTR Class - Name of provider
|
|
// long lFlags - Enumeration flags.
|
|
// IWbemContext __RPC_FAR *pCtxt - Context pointer
|
|
// IWbemObjectSink __RPC_FAR *pResponseHandler - Response
|
|
// handler.
|
|
//
|
|
// Outputs: None.
|
|
//
|
|
// Returns: SCCODE - COM Status.
|
|
//
|
|
// Comments: None.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT CWbemProviderGlue::CreateInstanceEnumAsync(
|
|
|
|
const BSTR a_bstrClass,
|
|
long lFlags,
|
|
IWbemContext __RPC_FAR *pCtx,
|
|
IWbemObjectSink __RPC_FAR *pResponseHandler
|
|
)
|
|
{
|
|
// make sure we don't disappear while running
|
|
AddRef();
|
|
|
|
CSetStructuredExceptionHandler t_ExceptionHandler;
|
|
|
|
#ifdef PROVIDER_INSTRUMENTATION
|
|
StopWatch stopWatch(CHString(IDS_CREATEINSTANCEENUM) + CHString(Class));
|
|
stopWatch.Start(StopWatch::FrameworkTimer);
|
|
#endif
|
|
|
|
HRESULT hr = WBEM_E_INVALID_CLASS;
|
|
IWbemClassObjectPtr pStatusObject;
|
|
bool bSendStatus = true;
|
|
|
|
try
|
|
{
|
|
if (IsVerboseLoggingEnabled())
|
|
{
|
|
LogMessage3(L"%s%s", IDS_CREATEINSTANCEENUM, a_bstrClass);
|
|
}
|
|
|
|
// Check for per-property gets
|
|
CFrameworkQueryEx CQuery;
|
|
hr = CQuery.Init(NULL, pCtx, a_bstrClass, m_strNamespace);
|
|
|
|
// Note that we AREN'T calling Init2, which means if they specified "__RELPATH"
|
|
// as their property, we won't expand that out to the key names. However, since
|
|
// we are going to call ExecQuery, and it reprocesses the query and DOES call
|
|
// Init2, this isn't an issue.
|
|
// CQuery.Init2(pWbemClassObject);
|
|
|
|
// If they are doing per-property gets, then turn this into a query.
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (CQuery.AllPropertiesAreRequired())
|
|
{
|
|
// Search for the class name in our map of providers, we know which
|
|
// namespace we are when we get constructed.
|
|
// pProvider doesn't get addref'ed, so no release necessary
|
|
Provider *pProvider = SearchMapForProvider( a_bstrClass, m_strNamespace );
|
|
|
|
if ( NULL != pProvider )
|
|
{
|
|
// Now create an External Method Context object and go to town
|
|
ExternalMethodContextPtr pContext (new ExternalMethodContext( pResponseHandler, pCtx, this ), false);
|
|
|
|
if ( NULL != pContext )
|
|
{
|
|
CWbemGlueImpersonation impersonate;
|
|
if SUCCEEDED ( hr = impersonate.IsImpersonated () )
|
|
{
|
|
// Set up to call FlushAll
|
|
AddFlushPtr(pProvider);
|
|
|
|
WCHAR wszName[UNLEN + DNLEN + 1 + 1] = {0};
|
|
WCHAR wszName2[UNLEN + DNLEN + 1 + 1] = {0}; // domain + \ + name + null
|
|
DWORD dwLen = UNLEN + DNLEN + 1 + 1;
|
|
|
|
GetUserNameEx(NameSamCompatible, wszName, &dwLen);
|
|
|
|
#ifdef PROVIDER_INSTRUMENTATION
|
|
pContext->pStopWatch = &stopWatch;
|
|
#endif
|
|
hr = pProvider->CreateInstanceEnum( pContext, lFlags );
|
|
|
|
dwLen = UNLEN + DNLEN + 1 + 1;
|
|
|
|
GetUserNameEx(NameSamCompatible, wszName2, &dwLen);
|
|
|
|
if (wcscmp(wszName, wszName2) != 0)
|
|
{
|
|
ASSERT_BREAK(IMPERSONATION_REVERTED);
|
|
LogErrorMessage4(L"Warning! User name at exit (%s) != user name at entry (%s) for %s",
|
|
wszName2, wszName, a_bstrClass);
|
|
}
|
|
}
|
|
pStatusObject.Attach(pContext->GetStatusObject());
|
|
}
|
|
else
|
|
{
|
|
throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LogErrorMessage4(L"%s (%s:%s)", IDS_PROVIDERNOTFOUND, (LPCWSTR)m_strNamespace, a_bstrClass);
|
|
hr = WBEM_E_INVALID_CLASS;
|
|
bSendStatus = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bstr_t bstrtQuery = CQuery.GetQuery();
|
|
|
|
hr =
|
|
ExecQueryAsync(
|
|
L"WQL",
|
|
bstrtQuery,
|
|
lFlags,
|
|
pCtx,
|
|
pResponseHandler);
|
|
|
|
// Since execquery sent whatever status is necessary
|
|
bSendStatus = false;
|
|
}
|
|
|
|
}
|
|
|
|
if (IsVerboseLoggingEnabled())
|
|
{
|
|
if (SUCCEEDED(hr))
|
|
LogMessage3(L"%s%s - Succeeded", IDS_CREATEINSTANCEENUM, a_bstrClass);
|
|
else
|
|
LogMessage4(L"%s%s - FAILED (%x)", IDS_CREATEINSTANCEENUM, a_bstrClass, hr);
|
|
}
|
|
}
|
|
|
|
catch ( CFramework_Exception e_FR )
|
|
{
|
|
ASSERT_BREAK(FRAMEWORK_EXCEPTION);
|
|
hr = WBEM_E_PROVIDER_FAILURE;
|
|
}
|
|
catch ( CHeap_Exception e_HE )
|
|
{
|
|
ASSERT_BREAK(MEMORY_EXHAUSTED);
|
|
hr = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
catch(CStructured_Exception e_SE)
|
|
{
|
|
ASSERT_BREAK(STRUCTURED_EXCEPTION);
|
|
hr = WBEM_E_PROVIDER_FAILURE;
|
|
}
|
|
catch ( ... )
|
|
{
|
|
ASSERT_BREAK(UNSPECIFIED_EXCEPTION);
|
|
hr = WBEM_E_PROVIDER_FAILURE;
|
|
}
|
|
|
|
if ((hr != WBEM_E_INVALID_CLASS) && (hr != WBEM_E_UNSUPPORTED_PARAMETER) && bSendStatus)
|
|
{
|
|
|
|
#ifdef PROVIDER_INSTRUMENTATION
|
|
stopWatch.Start(StopWatch::WinMgmtTimer);
|
|
#endif
|
|
|
|
pResponseHandler->SetStatus( 0, hr, NULL, pStatusObject );
|
|
|
|
#ifdef PROVIDER_INSTRUMENTATION
|
|
stopWatch.Start(StopWatch::FrameworkTimer);
|
|
#endif
|
|
|
|
hr = WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
Release();
|
|
#ifdef PROVIDER_INSTRUMENTATION
|
|
stopWatch.Stop();
|
|
stopWatch.LogResults();
|
|
#endif
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::GetObjectAsync
|
|
//
|
|
// Parses the supplied object path and hands the request off
|
|
// to the appropriate provider.
|
|
//
|
|
// Inputs: const BSTR ObjPath - Object Path containing
|
|
// keys to required object.
|
|
// long lFlags - Get Object flags.
|
|
// IWbemContext __RPC_FAR *pCtxt - Context pointer
|
|
// IWbemObjectSink __RPC_FAR *pResponseHandler - Response
|
|
// handler.
|
|
//
|
|
// Outputs: None.
|
|
//
|
|
// Returns: SCCODE - COM Status.
|
|
//
|
|
// Comments: None.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT CWbemProviderGlue::GetObjectAsync(
|
|
|
|
const BSTR ObjectPath,
|
|
long lFlags,
|
|
IWbemContext __RPC_FAR *pCtx,
|
|
IWbemObjectSink __RPC_FAR *pResponseHandler
|
|
)
|
|
{
|
|
// make sure we don't disappear while running
|
|
AddRef();
|
|
|
|
CSetStructuredExceptionHandler t_ExceptionHandler;
|
|
|
|
#ifdef PROVIDER_INSTRUMENTATION
|
|
StopWatch stopWatch(CHString(IDS_GETOBJECTASYNC) + CHString(ObjectPath));
|
|
stopWatch.Start(StopWatch::FrameworkTimer);
|
|
#endif
|
|
|
|
HRESULT hr = WBEM_E_FAILED;
|
|
bool bLocalError = false;
|
|
IWbemClassObjectPtr pStatusObject;
|
|
ParsedObjectPath *pParsedPath = NULL;
|
|
CObjectPathParser objpathParser;
|
|
|
|
try
|
|
{
|
|
if (IsVerboseLoggingEnabled())
|
|
{
|
|
LogMessage3(L"%s%s", IDS_GETOBJECTASYNC, ObjectPath);
|
|
}
|
|
|
|
// Parse the object path passed to us by CIMOM
|
|
// ==========================================
|
|
int nStatus = objpathParser.Parse( ObjectPath, &pParsedPath );
|
|
|
|
if ( 0 == nStatus )
|
|
{
|
|
|
|
// Now try to find the provider based on the class name
|
|
// pProvider doesn't get addref'ed, so no release necessary
|
|
Provider *pProvider = SearchMapForProvider( pParsedPath->m_pClass, m_strNamespace );
|
|
|
|
// If we got a provider, let it handle itself like a grown-up provider
|
|
// should.
|
|
|
|
if ( NULL != pProvider )
|
|
{
|
|
// Now create an External Method Context object and go to town
|
|
|
|
ExternalMethodContextPtr pContext (new ExternalMethodContext( pResponseHandler, pCtx, this ), false);
|
|
|
|
if ( NULL != pContext )
|
|
{
|
|
#ifdef PROVIDER_INSTRUMENTATION
|
|
pContext->pStopWatch = &stopWatch;
|
|
#endif
|
|
CWbemGlueImpersonation impersonate;
|
|
if SUCCEEDED ( hr = impersonate.IsImpersonated () )
|
|
{
|
|
// Set up to call FlushAll
|
|
AddFlushPtr(pProvider);
|
|
|
|
WCHAR wszName[UNLEN + DNLEN + 1 + 1] = {0};
|
|
WCHAR wszName2[UNLEN + DNLEN + 1 + 1] = {0}; // domain + \ + name + null
|
|
DWORD dwLen = UNLEN + DNLEN + 1 + 1;
|
|
|
|
GetUserNameEx(NameSamCompatible, wszName, &dwLen);
|
|
|
|
hr = pProvider->GetObject( pParsedPath, pContext, lFlags );
|
|
dwLen = UNLEN + DNLEN + 1 + 1;
|
|
|
|
GetUserNameEx(NameSamCompatible, wszName2, &dwLen);
|
|
|
|
if (wcscmp(wszName, wszName2) != 0)
|
|
{
|
|
ASSERT_BREAK(IMPERSONATION_REVERTED);
|
|
LogErrorMessage4(L"Warning! User name at exit (%s) != user name at entry (%s) for %s",
|
|
wszName2, wszName, ObjectPath);
|
|
}
|
|
}
|
|
|
|
pStatusObject.Attach(pContext->GetStatusObject());
|
|
}
|
|
else
|
|
{
|
|
throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
LogErrorMessage4(L"%s (%s:%s)", IDS_PROVIDERNOTFOUND, (LPCWSTR)m_strNamespace, pParsedPath->m_pClass);
|
|
hr = WBEM_E_INVALID_CLASS;
|
|
bLocalError = true;
|
|
}
|
|
|
|
}
|
|
|
|
if (IsVerboseLoggingEnabled())
|
|
{
|
|
if (SUCCEEDED(hr))
|
|
LogMessage3(L"%s%s - Succeeded", IDS_GETOBJECTASYNC, ObjectPath);
|
|
else
|
|
LogMessage4(L"%s%s - FAILED (%x)", IDS_GETOBJECTASYNC, ObjectPath, hr);
|
|
}
|
|
|
|
}
|
|
catch ( CFramework_Exception e_FR )
|
|
{
|
|
ASSERT_BREAK(FRAMEWORK_EXCEPTION);
|
|
hr = WBEM_E_PROVIDER_FAILURE;
|
|
}
|
|
catch ( CHeap_Exception e_HE )
|
|
{
|
|
ASSERT_BREAK(MEMORY_EXHAUSTED);
|
|
hr = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
catch(CStructured_Exception e_SE)
|
|
{
|
|
ASSERT_BREAK(STRUCTURED_EXCEPTION);
|
|
hr = WBEM_E_PROVIDER_FAILURE;
|
|
}
|
|
catch ( ... )
|
|
{
|
|
ASSERT_BREAK(UNSPECIFIED_EXCEPTION);
|
|
hr = WBEM_E_PROVIDER_FAILURE;
|
|
}
|
|
|
|
if ((hr != WBEM_E_INVALID_CLASS) && (hr != WBEM_E_UNSUPPORTED_PARAMETER) && !bLocalError)
|
|
{
|
|
#ifdef PROVIDER_INSTRUMENTATION
|
|
stopWatch.Start(StopWatch::WinMgmtTimer);
|
|
#endif
|
|
pResponseHandler->SetStatus( 0, hr, NULL, pStatusObject );
|
|
#ifdef PROVIDER_INSTRUMENTATION
|
|
stopWatch.Start(StopWatch::FrameworkTimer);
|
|
#endif
|
|
hr = WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
// Clean up the Parsed Path
|
|
if (pParsedPath)
|
|
{
|
|
objpathParser.Free( pParsedPath );
|
|
}
|
|
|
|
Release();
|
|
#ifdef PROVIDER_INSTRUMENTATION
|
|
stopWatch.Stop();
|
|
stopWatch.LogResults();
|
|
#endif
|
|
return hr;
|
|
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::PutInstanceAsync
|
|
//
|
|
// Locates the provider for the specified class name and
|
|
// calls its CreateInstanceEnum function.
|
|
//
|
|
// Inputs: IWbemClassObject __RPC_FAR *pInst - Instance whose
|
|
// values to use.
|
|
// long lFlags - PutInstance flags.
|
|
// IWbemContext __RPC_FAR *pCtxt - Context pointer
|
|
// IWbemObjectSink __RPC_FAR *pResponseHandler - Response
|
|
// handler.
|
|
//
|
|
// Outputs: None.
|
|
//
|
|
// Returns: SCCODE - COM Status.
|
|
//
|
|
// Comments: None.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT CWbemProviderGlue::PutInstanceAsync(
|
|
|
|
IWbemClassObject __RPC_FAR *pInst,
|
|
long lFlags,
|
|
IWbemContext __RPC_FAR *pCtx,
|
|
IWbemObjectSink __RPC_FAR *pResponseHandler
|
|
)
|
|
{
|
|
// make sure we don't disappear while running
|
|
AddRef();
|
|
|
|
CSetStructuredExceptionHandler t_ExceptionHandler;
|
|
|
|
HRESULT hr = WBEM_E_INVALID_CLASS;
|
|
variant_t vClass;
|
|
bool bLocalError = false;
|
|
IWbemClassObjectPtr pStatusObject;
|
|
|
|
try
|
|
{
|
|
// Set up to get the class name of the instance being passed to us
|
|
// ask the framework if it has this class registered for support
|
|
// ===============================================================
|
|
|
|
// Get the class name
|
|
pInst->Get( IDS_CLASS, 0, &vClass, NULL, NULL );
|
|
|
|
if (IsVerboseLoggingEnabled())
|
|
{
|
|
LogMessage3(L"%s%s", IDS_PUTINSTANCEASYNC, vClass.bstrVal);
|
|
}
|
|
|
|
// pProvider doesn't get addref'ed, so no release necessary
|
|
Provider *pProvider = SearchMapForProvider( vClass.bstrVal, m_strNamespace );
|
|
|
|
// If we got a provider, let it handle itself like a grown-up provider
|
|
// should.
|
|
if ( NULL != pProvider )
|
|
{
|
|
// Now create an External Method Context object and go to town
|
|
ExternalMethodContextPtr pContext (new ExternalMethodContext( pResponseHandler, pCtx, this ), false);
|
|
|
|
if ( NULL != pContext )
|
|
{
|
|
IWbemClassObjectPtr pInstPostProcess;
|
|
if (SUCCEEDED(hr = PreProcessPutInstanceParms(pInst, &pInstPostProcess, pCtx)))
|
|
{
|
|
CWbemGlueImpersonation impersonate;
|
|
if SUCCEEDED ( hr = impersonate.IsImpersonated () )
|
|
{
|
|
// Set up to call FlushAll
|
|
AddFlushPtr(pProvider);
|
|
|
|
WCHAR wszName[UNLEN + DNLEN + 1 + 1] = {0};
|
|
WCHAR wszName2[UNLEN + DNLEN + 1 + 1] = {0}; // domain + \ + name + null
|
|
DWORD dwLen = UNLEN + DNLEN + 1 + 1;
|
|
|
|
GetUserNameEx(NameSamCompatible, wszName, &dwLen);
|
|
|
|
hr = pProvider->PutInstance( pInstPostProcess, lFlags, pContext );
|
|
|
|
dwLen = UNLEN + DNLEN + 1 + 1;
|
|
|
|
GetUserNameEx(NameSamCompatible, wszName2, &dwLen);
|
|
|
|
if (wcscmp(wszName, wszName2) != 0)
|
|
{
|
|
ASSERT_BREAK(IMPERSONATION_REVERTED);
|
|
LogErrorMessage4(L"Warning! User name at exit (%s) != user name at entry (%s) for %s",
|
|
wszName2, wszName, vClass.bstrVal);
|
|
}
|
|
}
|
|
}
|
|
pStatusObject.Attach(pContext->GetStatusObject());
|
|
}
|
|
else
|
|
{
|
|
throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LogErrorMessage4(L"%s (%s:%s)", IDS_PROVIDERNOTFOUND, (LPCWSTR)m_strNamespace, vClass.bstrVal);
|
|
hr = WBEM_E_INVALID_CLASS;
|
|
bLocalError = true;
|
|
}
|
|
|
|
|
|
if (IsVerboseLoggingEnabled())
|
|
{
|
|
if (SUCCEEDED(hr))
|
|
LogMessage3(L"%s%s - Succeeded", IDS_PUTINSTANCEASYNC, vClass.bstrVal);
|
|
else
|
|
LogMessage4(L"%s%s - FAILED (%x)", IDS_PUTINSTANCEASYNC, vClass.bstrVal, hr);
|
|
}
|
|
}
|
|
|
|
catch ( CFramework_Exception e_FR )
|
|
{
|
|
ASSERT_BREAK(FRAMEWORK_EXCEPTION);
|
|
hr = WBEM_E_PROVIDER_FAILURE;
|
|
}
|
|
catch ( CHeap_Exception e_HE )
|
|
{
|
|
ASSERT_BREAK(MEMORY_EXHAUSTED);
|
|
hr = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
catch(CStructured_Exception e_SE)
|
|
{
|
|
ASSERT_BREAK(STRUCTURED_EXCEPTION);
|
|
hr = WBEM_E_PROVIDER_FAILURE;
|
|
}
|
|
catch ( ... )
|
|
{
|
|
ASSERT_BREAK(UNSPECIFIED_EXCEPTION);
|
|
hr = WBEM_E_PROVIDER_FAILURE;
|
|
}
|
|
|
|
if ((hr != WBEM_E_INVALID_CLASS) && (hr != WBEM_E_UNSUPPORTED_PARAMETER) && !bLocalError)
|
|
{
|
|
pResponseHandler->SetStatus( 0, hr, NULL, pStatusObject );
|
|
hr = WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
Release();
|
|
return hr;
|
|
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::PreProcessPutInstanceParms()
|
|
//
|
|
// IF __PUT_EXT_PROPERTIES is specified, will parse out the intended properties
|
|
// and set to NULL those props that are not explicitly being put.
|
|
//
|
|
// Inputs: [IN] IWbemClassObject __RPC_FAR *pInstIn - Instance whose values to use.
|
|
// [OUT] IWbemClassObject __RPC_FAR **pInstOut - processed instance
|
|
// IWbemContext __RPC_FAR *pCtxt - Context pointer
|
|
//
|
|
// Outputs: None.
|
|
//
|
|
// Returns: WBEM_S_NO_ERROR if the only extension specified is __PUT_EXT_PROPERTIES
|
|
// or if no extensions are specified
|
|
// WBEM_E_UNSUPPORTED_PUT_EXTENSION if any other flag is set.
|
|
// WBEM_E_SEVERE_SCREWUP if some other darn thing happened.
|
|
//
|
|
// Comments: You may get a different IWbemObject out than you put in
|
|
// it's your responsibility to release it.
|
|
// On error - pInstOut is undefined.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
HRESULT CWbemProviderGlue::PreProcessPutInstanceParms(
|
|
|
|
IWbemClassObject __RPC_FAR *pInstIn,
|
|
IWbemClassObject __RPC_FAR **pInstOut,
|
|
IWbemContext __RPC_FAR *pCtx
|
|
)
|
|
{
|
|
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
// Variant_t handles the VariantInit/VariantClear
|
|
variant_t vValue;
|
|
|
|
if (
|
|
pCtx != NULL &&
|
|
SUCCEEDED(hr = pCtx->GetValue( L"__PUT_EXTENSIONS", 0, &vValue)) &&
|
|
V_VT(&vValue) == VT_BOOL &&
|
|
V_BOOL(&vValue) == VARIANT_TRUE
|
|
)
|
|
{
|
|
// easy checks first, are there unsupported parms?
|
|
vValue.Clear();
|
|
if (SUCCEEDED(hr = pCtx->GetValue( L"__PUT_EXT_STRICT_NULLS", 0, &vValue))
|
|
&& (V_VT(&vValue) == VT_BOOL)
|
|
&& (V_BOOL(&vValue) == VARIANT_TRUE))
|
|
hr = WBEM_E_UNSUPPORTED_PUT_EXTENSION;
|
|
else
|
|
{
|
|
vValue.Clear();
|
|
if (SUCCEEDED(hr = pCtx->GetValue( L"__PUT_EXT_ATOMIC", 0, &vValue))
|
|
&& (V_VT(&vValue) == VT_BOOL)
|
|
&& (V_BOOL(&vValue) == VARIANT_TRUE))
|
|
hr = WBEM_E_UNSUPPORTED_PUT_EXTENSION;
|
|
}
|
|
|
|
vValue.Clear();
|
|
if ((SUCCEEDED(hr) || (hr != WBEM_E_UNSUPPORTED_PUT_EXTENSION))
|
|
&& SUCCEEDED(hr = pCtx->GetValue( L"__PUT_EXT_PROPERTIES", 0, &vValue)))
|
|
{
|
|
if (V_VT(&vValue) == (VT_BSTR|VT_ARRAY))
|
|
hr = NullOutUnsetProperties(pInstIn, pInstOut, vValue);
|
|
else
|
|
hr = WBEM_E_INVALID_PARAMETER;
|
|
}
|
|
else if (hr == WBEM_E_NOT_FOUND)
|
|
{
|
|
// well, if we've never heard of it, it MUST be wrong...
|
|
hr = WBEM_E_UNSUPPORTED_PUT_EXTENSION;
|
|
}
|
|
}
|
|
else if (hr == WBEM_E_NOT_FOUND)
|
|
{
|
|
// no extensions - no problems.
|
|
// out interface is same as in interface
|
|
hr = WBEM_S_NO_ERROR;
|
|
*pInstOut = pInstIn;
|
|
(*pInstOut)->AddRef();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::NullOutUnsetProperties
|
|
//
|
|
// returns a copy of the input class, any properties whose names are listed
|
|
// in the variant are set to NULL in the output class
|
|
//
|
|
//
|
|
// Inputs: IWbemClassObject __RPC_FAR *pInst - Instance whose
|
|
// values to NULL
|
|
// VARIANT contains names to not NULL out.
|
|
//
|
|
// Outputs: None.
|
|
//
|
|
// Returns: the ubiquitous HRESULT
|
|
//
|
|
// Comments: Assumes you've done your homework and the Variant
|
|
// is a BSTR Array containing property names.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
HRESULT CWbemProviderGlue::NullOutUnsetProperties(
|
|
|
|
IWbemClassObject __RPC_FAR *pInstIn,
|
|
IWbemClassObject __RPC_FAR **pInstOut,
|
|
const VARIANT& vValue
|
|
)
|
|
{
|
|
HRESULT hRes = WBEM_S_NO_ERROR;
|
|
|
|
// get ourselves a copy to work with
|
|
CInstancePtr pInstance;
|
|
|
|
// Variant_t handles the VariantInit/VariantClear
|
|
variant_t vName;
|
|
variant_t vNameSpace;
|
|
|
|
hRes = pInstIn->Get(IDS_CLASS, 0, &vName, NULL, NULL);
|
|
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
hRes = pInstIn->Get(L"__NAMESPACE", 0, &vNameSpace, NULL, NULL);
|
|
}
|
|
|
|
if (SUCCEEDED(hRes) && SUCCEEDED( hRes = GetEmptyInstance(vName.bstrVal, &pInstance, vNameSpace.bstrVal)))
|
|
{
|
|
// and off we go...
|
|
SAFEARRAY *pNames = vValue.parray;
|
|
long nBiggestName;
|
|
if (SUCCEEDED(hRes = SafeArrayGetUBound(pNames, 1, &nBiggestName)))
|
|
{
|
|
BSTR t_bstrName = NULL ;
|
|
*pInstOut = pInstance->GetClassObjectInterface();
|
|
|
|
variant_t value;
|
|
|
|
// wander through the names, for every one we find
|
|
// copy the property value to the out pointer
|
|
for (long i = 0; i <= nBiggestName; i++)
|
|
{
|
|
if (SUCCEEDED(SafeArrayGetElement( pNames, &i, &t_bstrName )))
|
|
{
|
|
OnDeleteIf<BSTR,VOID(*)(BSTR),SysFreeString> smartt_bstrName(t_bstrName);
|
|
|
|
pInstIn->Get( t_bstrName, 0, &value, NULL, NULL);
|
|
(*pInstOut)->Put( t_bstrName, 0, &value, 0);
|
|
}
|
|
}
|
|
|
|
// and, oh what the heck - let's copy the keys, too...
|
|
SAFEARRAY *pKeyNames = NULL;
|
|
if (SUCCEEDED(hRes = pInstIn->GetNames(NULL, WBEM_FLAG_KEYS_ONLY, NULL, &pKeyNames)))
|
|
{
|
|
OnDelete<SAFEARRAY *,HRESULT(*)(SAFEARRAY *),SafeArrayDestroy> smartpKeyNames(pKeyNames);
|
|
|
|
SafeArrayGetUBound(pKeyNames, 1, &nBiggestName);
|
|
for (i = 0; i <= nBiggestName; i++)
|
|
{
|
|
if (SUCCEEDED(SafeArrayGetElement( pKeyNames, &i, &t_bstrName )))
|
|
{
|
|
OnDeleteIf<BSTR,VOID(*)(BSTR),SysFreeString> smartt_bstrName(t_bstrName);
|
|
|
|
pInstIn->Get( t_bstrName, 0, &value, NULL, NULL );
|
|
(*pInstOut)->Put( t_bstrName, 0, &value, 0 );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// failed to get array upper bound!
|
|
hRes = WBEM_E_FAILED;
|
|
}
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::DeleteInstanceAsync
|
|
//
|
|
// Locates the provider for the specified class name and
|
|
// calls its DeleteInstance function.
|
|
//
|
|
// Inputs: IWbemClassObject __RPC_FAR *pInst - Instance whose
|
|
// values to use.
|
|
// long lFlags - PutInstance flags.
|
|
// IWbemContext __RPC_FAR *pCtxt - Context pointer
|
|
// IWbemObjectSink __RPC_FAR *pResponseHandler - Response
|
|
// handler.
|
|
//
|
|
// Outputs: None.
|
|
//
|
|
// Returns: SCCODE - COM Status.
|
|
//
|
|
// Comments: None.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
HRESULT CWbemProviderGlue::DeleteInstanceAsync(
|
|
|
|
const BSTR ObjectPath,
|
|
long lFlags,
|
|
IWbemContext __RPC_FAR *pCtx,
|
|
IWbemObjectSink __RPC_FAR *pResponseHandler
|
|
)
|
|
{
|
|
// make sure we don't disappear while running
|
|
AddRef();
|
|
|
|
CSetStructuredExceptionHandler t_ExceptionHandler;
|
|
|
|
HRESULT hr = WBEM_E_FAILED;
|
|
bool bLocalError = false;
|
|
IWbemClassObjectPtr pStatusObject;
|
|
|
|
ParsedObjectPath *pParsedPath = NULL;
|
|
CObjectPathParser objpathParser;
|
|
|
|
try
|
|
{
|
|
if (IsVerboseLoggingEnabled())
|
|
{
|
|
LogMessage3(L"%s%s", IDS_DELETEINSTANCEASYNC, ObjectPath);
|
|
}
|
|
|
|
// Parse the object path passed to us by CIMOM
|
|
// ==========================================
|
|
int nStatus = objpathParser.Parse( ObjectPath, &pParsedPath );
|
|
|
|
if ( 0 == nStatus )
|
|
{
|
|
// Now try to find the provider based on the class name
|
|
// pProvider doesn't get addref'ed, so no release necessary
|
|
Provider *pProvider = SearchMapForProvider( pParsedPath->m_pClass, m_strNamespace );
|
|
|
|
// If we got a provider, let it handle itself like a grown-up provider
|
|
// should.
|
|
|
|
if ( NULL != pProvider )
|
|
{
|
|
// Now create an External Method Context object and go to town
|
|
|
|
ExternalMethodContextPtr pContext (new ExternalMethodContext( pResponseHandler, pCtx, this ), false);
|
|
|
|
if ( NULL != pContext )
|
|
{
|
|
CWbemGlueImpersonation impersonate;
|
|
if SUCCEEDED ( hr = impersonate.IsImpersonated () )
|
|
{
|
|
// Set up to call FlushAll
|
|
AddFlushPtr(pProvider);
|
|
|
|
WCHAR wszName[UNLEN + DNLEN + 1 + 1] = {0};
|
|
WCHAR wszName2[UNLEN + DNLEN + 1 + 1] = {0}; // domain + \ + name + null
|
|
DWORD dwLen = UNLEN + DNLEN + 1 + 1;
|
|
|
|
GetUserNameEx(NameSamCompatible, wszName, &dwLen);
|
|
|
|
hr = pProvider->DeleteInstance( pParsedPath, lFlags, pContext );
|
|
|
|
dwLen = UNLEN + DNLEN + 1 + 1;
|
|
|
|
GetUserNameEx(NameSamCompatible, wszName2, &dwLen);
|
|
|
|
if (wcscmp(wszName, wszName2) != 0)
|
|
{
|
|
ASSERT_BREAK(IMPERSONATION_REVERTED);
|
|
LogErrorMessage4(L"Warning! User name at exit (%s) != user name at entry (%s) for %s",
|
|
wszName2, wszName, ObjectPath);
|
|
}
|
|
}
|
|
pStatusObject.Attach(pContext->GetStatusObject());
|
|
}
|
|
else
|
|
{
|
|
throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
hr = WBEM_E_INVALID_CLASS;
|
|
LogErrorMessage4(L"%s (%s:%s)", IDS_PROVIDERNOTFOUND, (LPCWSTR)m_strNamespace, pParsedPath->m_pClass);
|
|
bLocalError = true;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
LogErrorMessage3(L"%s (%s)", IDS_COULDNOTPARSE, ObjectPath);
|
|
bLocalError = true;
|
|
}
|
|
|
|
if (IsVerboseLoggingEnabled())
|
|
{
|
|
if (SUCCEEDED(hr))
|
|
LogMessage3(L"%s%s - Succeeded", IDS_DELETEINSTANCEASYNC, ObjectPath);
|
|
else
|
|
LogMessage4(L"%s%s - FAILED (%x)", IDS_DELETEINSTANCEASYNC, ObjectPath, hr);
|
|
}
|
|
}
|
|
|
|
catch ( CFramework_Exception e_FR )
|
|
{
|
|
ASSERT_BREAK(FRAMEWORK_EXCEPTION);
|
|
hr = WBEM_E_PROVIDER_FAILURE;
|
|
}
|
|
catch ( CHeap_Exception e_HE )
|
|
{
|
|
ASSERT_BREAK(MEMORY_EXHAUSTED);
|
|
hr = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
catch(CStructured_Exception e_SE)
|
|
{
|
|
ASSERT_BREAK(STRUCTURED_EXCEPTION);
|
|
hr = WBEM_E_PROVIDER_FAILURE;
|
|
}
|
|
catch ( ... )
|
|
{
|
|
ASSERT_BREAK(UNSPECIFIED_EXCEPTION);
|
|
hr = WBEM_E_PROVIDER_FAILURE;
|
|
}
|
|
|
|
if ((hr != WBEM_E_INVALID_CLASS) && (hr != WBEM_E_UNSUPPORTED_PARAMETER) && !bLocalError)
|
|
{
|
|
pResponseHandler->SetStatus( 0, hr, NULL, pStatusObject);
|
|
hr = WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
// Clean up the Parsed Path
|
|
if (pParsedPath)
|
|
{
|
|
objpathParser.Free( pParsedPath );
|
|
}
|
|
|
|
Release();
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::ExecMethodAsync
|
|
//
|
|
// Locates the provider for the specified class name and
|
|
// calls its ExecMethod function.
|
|
//
|
|
// Inputs:
|
|
// const BSTR ObjectPath, - Object path on which to execute the method
|
|
// const BSTR MethodName, - Name of the method to execute
|
|
// long lFlags, - Any flags
|
|
// IWbemContext __RPC_FAR *pCtx,
|
|
// IWbemClassObject __RPC_FAR *pInParams, - Pointer to IWbemClassObject
|
|
// that contains parms
|
|
// IWbemObjectSink __RPC_FAR *pResponseHandler)
|
|
//
|
|
// Outputs: None.
|
|
//
|
|
// Returns: SCCODE - COM Status.
|
|
//
|
|
// Comments: None.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT CWbemProviderGlue::ExecMethodAsync(
|
|
|
|
const BSTR ObjectPath,
|
|
const BSTR MethodName,
|
|
long lFlags,
|
|
IWbemContext __RPC_FAR *pCtx,
|
|
IWbemClassObject __RPC_FAR *pInParams,
|
|
IWbemObjectSink __RPC_FAR *pResponseHandler
|
|
)
|
|
{
|
|
// make sure we don't disappear while running
|
|
AddRef();
|
|
|
|
CSetStructuredExceptionHandler t_ExceptionHandler;
|
|
|
|
#ifdef PROVIDER_INSTRUMENTATION
|
|
StopWatch stopWatch(CHString(IDS_EXECMETHODASYNC) + CHString(ObjectPath) + CHString(MethodName));
|
|
stopWatch.Start(StopWatch::FrameworkTimer);
|
|
#endif
|
|
|
|
HRESULT hr = WBEM_E_FAILED;
|
|
bool bLocalError = false;
|
|
IWbemClassObjectPtr pStatusObject;
|
|
|
|
ParsedObjectPath *pParsedPath = NULL;
|
|
CObjectPathParser objpathParser;
|
|
|
|
try
|
|
{
|
|
if (IsVerboseLoggingEnabled())
|
|
{
|
|
LogMessage4(L"%s%s.%s", IDS_EXECMETHODASYNC, ObjectPath, MethodName);
|
|
}
|
|
|
|
// Parse the object path passed to us by CIMOM
|
|
// ==========================================
|
|
int nStatus = objpathParser.Parse( ObjectPath, &pParsedPath );
|
|
|
|
if ( 0 == nStatus )
|
|
{
|
|
// Now try to find the provider based on the class name
|
|
// pProvider doesn't get addref'ed, so no release necessary
|
|
Provider *pProvider = SearchMapForProvider( pParsedPath->m_pClass, m_strNamespace );
|
|
|
|
// If we got a provider, let it handle itself like a grown-up provider
|
|
// should.
|
|
|
|
if ( NULL != pProvider )
|
|
{
|
|
IWbemClassObjectPtr pOutClass;
|
|
IWbemClassObjectPtr pOutParams;
|
|
CInstancePtr COutParam;
|
|
CInstancePtr CInParam;
|
|
hr = WBEM_S_NO_ERROR;
|
|
|
|
// Now create an External Method Context object and go to town
|
|
ExternalMethodContextPtr pContext (new ExternalMethodContext( pResponseHandler, pCtx, this ), false);
|
|
#ifdef PROVIDER_INSTRUMENTATION
|
|
pContext->pStopWatch = &stopWatch;
|
|
#endif
|
|
|
|
// Check for out of memory
|
|
if (NULL == pContext)
|
|
{
|
|
throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
|
|
}
|
|
|
|
// add check to ensure that we do not call a static method
|
|
// on an instance of a class.
|
|
if (SUCCEEDED(hr) && pParsedPath->IsInstance())
|
|
{
|
|
IWbemClassObjectPtr pObj(pProvider->GetClassObjectInterface(pContext), false);
|
|
if (pObj)
|
|
{
|
|
IWbemQualifierSetPtr pSet;
|
|
#ifdef PROVIDER_INSTRUMENTATION
|
|
stopWatch.Start(StopWatch::WinMgmtTimer);
|
|
#endif
|
|
if (SUCCEEDED(pObj->GetMethodQualifierSet(MethodName, &pSet)))
|
|
{
|
|
// disallow an instance to invoke a static method
|
|
#ifdef PROVIDER_INSTRUMENTATION
|
|
stopWatch.Start(StopWatch::WinMgmtTimer);
|
|
#endif
|
|
if (SUCCEEDED(pSet->Get( IDS_Static, 0, NULL, NULL)))
|
|
hr = WBEM_E_INVALID_METHOD;
|
|
#ifdef PROVIDER_INSTRUMENTATION
|
|
stopWatch.Start(StopWatch::FrameworkTimer);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
// If there are in params, convert them to a cinstance.
|
|
if (SUCCEEDED(hr) && (NULL != pInParams) )
|
|
{
|
|
CInParam.Attach(new CInstance(pInParams, pContext));
|
|
|
|
if (NULL == CInParam)
|
|
{
|
|
throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
|
|
}
|
|
}
|
|
|
|
// Get the output class for the method
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IWbemClassObjectPtr pObj(pProvider->GetClassObjectInterface(pContext), false);
|
|
if (pObj != NULL)
|
|
{
|
|
#ifdef PROVIDER_INSTRUMENTATION
|
|
stopWatch.Start(StopWatch::WinMgmtTimer);
|
|
#endif
|
|
hr = pObj->GetMethod(MethodName, 0, NULL, &pOutClass);
|
|
#ifdef PROVIDER_INSTRUMENTATION
|
|
stopWatch.Start(StopWatch::FrameworkTimer);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
hr = WBEM_E_FAILED;
|
|
}
|
|
}
|
|
|
|
// If there is no output class, pOutClass is null (by design). So, if there was no error
|
|
// and we got an pOutClass, get an instance and wrap it in a CInstance
|
|
if (SUCCEEDED(hr) && (pOutClass != NULL))
|
|
{
|
|
#ifdef PROVIDER_INSTRUMENTATION
|
|
stopWatch.Start(StopWatch::WinMgmtTimer);
|
|
#endif
|
|
hr = pOutClass->SpawnInstance(0, &pOutParams);
|
|
#ifdef PROVIDER_INSTRUMENTATION
|
|
stopWatch.Start(StopWatch::FrameworkTimer);
|
|
#endif
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
COutParam.Attach(new CInstance(pOutParams, pContext));
|
|
|
|
// Out of memory
|
|
if (NULL == COutParam)
|
|
{
|
|
throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
CWbemGlueImpersonation impersonate;
|
|
if SUCCEEDED ( hr = impersonate.IsImpersonated () )
|
|
{
|
|
// Set up to call FlushAll
|
|
AddFlushPtr(pProvider);
|
|
|
|
WCHAR wszName[UNLEN + DNLEN + 1 + 1] = {0};
|
|
WCHAR wszName2[UNLEN + DNLEN + 1 + 1] = {0}; // domain + \ + name + null
|
|
DWORD dwLen = UNLEN + DNLEN + 1 + 1;
|
|
|
|
GetUserNameEx(NameSamCompatible, wszName, &dwLen);
|
|
|
|
hr = pProvider->ExecMethod( pParsedPath, MethodName, lFlags, CInParam, COutParam, pContext );
|
|
|
|
dwLen = UNLEN + DNLEN + 1 + 1;
|
|
|
|
GetUserNameEx(NameSamCompatible, wszName2, &dwLen);
|
|
|
|
if (wcscmp(wszName, wszName2) != 0)
|
|
{
|
|
ASSERT_BREAK(IMPERSONATION_REVERTED);
|
|
LogErrorMessage5(L"Warning! User name at exit (%s) != user name at entry (%s) for %s.%s",
|
|
wszName2, wszName, ObjectPath, MethodName);
|
|
}
|
|
}
|
|
}
|
|
|
|
// If there is an output object
|
|
if (COutParam != NULL)
|
|
{
|
|
|
|
// Only send back an output object if the method succeeded
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
|
|
// Send the object back
|
|
IWbemClassObjectPtr pObj(COutParam->GetClassObjectInterface(), false);
|
|
IWbemClassObject *pObj2 = (IWbemClassObject *)pObj;
|
|
#ifdef PROVIDER_INSTRUMENTATION
|
|
stopWatch.Start(StopWatch::WinMgmtTimer);
|
|
#endif
|
|
|
|
pResponseHandler->Indicate( 1, &pObj2);
|
|
#ifdef PROVIDER_INSTRUMENTATION
|
|
stopWatch.Start(StopWatch::FrameworkTimer);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
pStatusObject.Attach(pContext->GetStatusObject());
|
|
|
|
}
|
|
else
|
|
{
|
|
LogErrorMessage3(L"%s (%s)", IDS_PROVIDERNOTFOUND, pParsedPath->m_pClass);
|
|
hr = WBEM_E_INVALID_CLASS;
|
|
bLocalError = true;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
LogErrorMessage3(L"%s (%s)", IDS_COULDNOTPARSE, ObjectPath);
|
|
bLocalError = true;
|
|
}
|
|
|
|
if (IsVerboseLoggingEnabled())
|
|
{
|
|
if (SUCCEEDED(hr))
|
|
LogMessage4(L"%s%s.%s - Succeeded", IDS_EXECMETHODASYNC, ObjectPath, MethodName);
|
|
else
|
|
LogMessage5(L"%s%s.%s - FAILED (%x)", IDS_EXECMETHODASYNC, ObjectPath, MethodName, hr);
|
|
}
|
|
}
|
|
|
|
catch ( CFramework_Exception e_FR )
|
|
{
|
|
ASSERT_BREAK(FRAMEWORK_EXCEPTION);
|
|
hr = WBEM_E_PROVIDER_FAILURE;
|
|
}
|
|
catch ( CHeap_Exception e_HE )
|
|
{
|
|
ASSERT_BREAK(MEMORY_EXHAUSTED);
|
|
hr = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
catch(CStructured_Exception e_SE)
|
|
{
|
|
ASSERT_BREAK(STRUCTURED_EXCEPTION);
|
|
hr = WBEM_E_PROVIDER_FAILURE;
|
|
}
|
|
catch ( ... )
|
|
{
|
|
ASSERT_BREAK(UNSPECIFIED_EXCEPTION);
|
|
hr = WBEM_E_PROVIDER_FAILURE;
|
|
}
|
|
|
|
if ((hr != WBEM_E_INVALID_CLASS) && (hr != WBEM_E_UNSUPPORTED_PARAMETER) && !bLocalError)
|
|
{
|
|
#ifdef PROVIDER_INSTRUMENTATION
|
|
stopWatch.Start(StopWatch::WinMgmtTimer);
|
|
#endif
|
|
pResponseHandler->SetStatus( 0, hr, NULL, pStatusObject );
|
|
#ifdef PROVIDER_INSTRUMENTATION
|
|
stopWatch.Start(StopWatch::FrameworkTimer);
|
|
#endif
|
|
hr = WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
// Clean up the Parsed Path
|
|
if (pParsedPath)
|
|
{
|
|
objpathParser.Free( pParsedPath );
|
|
}
|
|
|
|
Release();
|
|
|
|
#ifdef PROVIDER_INSTRUMENTATION
|
|
stopWatch.Stop();
|
|
stopWatch.LogResults();
|
|
#endif
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::GetNamespaceConnection
|
|
//
|
|
// Establishes a connection to the supplied namespace by first
|
|
// assigning a default if needed, then searching our map, and if
|
|
// that fails, then actually connecting.
|
|
//
|
|
// Inputs: const BSTR NameSpace - NameSpace of provider
|
|
//
|
|
// Outputs: None.
|
|
//
|
|
// Returns: IWbemServices *pointer to IWbemServices corresponding
|
|
// to the connected namespace.
|
|
//
|
|
// Comments: Default Namespace is Root\\Default
|
|
//
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
IWbemServices *CWbemProviderGlue::GetNamespaceConnection(
|
|
|
|
LPCWSTR pwszNameSpace
|
|
)
|
|
{
|
|
ASSERT_BREAK(DEPRECATED);
|
|
|
|
bstr_t bstrNamespace(pwszNameSpace);
|
|
|
|
// Root\CimV2 is the default name space
|
|
if ( NULL == pwszNameSpace
|
|
|| L'\0' == *pwszNameSpace )
|
|
{
|
|
bstrNamespace = DEFAULT_NAMESPACE;
|
|
}
|
|
|
|
if (IsVerboseLoggingEnabled())
|
|
{
|
|
LogMessage3(L"%s%s", IDS_GETNAMESPACECONNECTION, (LPCWSTR)bstrNamespace);
|
|
}
|
|
|
|
IWbemLocatorPtr pIWbemLocator;
|
|
IWbemServices *pWbemServices = NULL;
|
|
|
|
HRESULT hRes = CoCreateInstance (
|
|
|
|
CLSID_WbemLocator, //CLSID_WbemAdministrativeLocator,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
|
|
IID_IUnknown,
|
|
( void ** ) &pIWbemLocator
|
|
) ;
|
|
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
hRes = pIWbemLocator->ConnectServer(bstrNamespace, // Namespace
|
|
NULL, // Userid
|
|
NULL, // PW
|
|
NULL, // Locale
|
|
0, // flags
|
|
NULL, // Authority
|
|
NULL, // Context
|
|
&pWbemServices
|
|
);
|
|
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
}
|
|
else
|
|
{
|
|
LogErrorMessage3(L"Failed to Connectserver to namespace %s (%x)", (LPCWSTR)bstrNamespace, hRes);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LogErrorMessage2(L"Failed to get locator (%x)", hRes);
|
|
}
|
|
|
|
return pWbemServices;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::FrameworkLogin
|
|
//
|
|
// Static entry point for providers to login to the framework,
|
|
// providing us with info for our map, and allowing us to return
|
|
// an IWbemServices pointer for the base provider class to
|
|
// manipulate to its heart's content.
|
|
//
|
|
// Inputs: LPCWSTR& strName - Name of object for map.
|
|
// Provider *pProvider - Pointer Name Maps to.
|
|
// LPCWSTR pszNameSpace - NameSpace of provider
|
|
//
|
|
// Outputs: None.
|
|
//
|
|
// Returns: None.
|
|
//
|
|
// Comments: None.
|
|
//
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
void CWbemProviderGlue::FrameworkLogin(
|
|
|
|
LPCWSTR a_szName,
|
|
Provider *a_pProvider,
|
|
LPCWSTR a_pszNameSpace
|
|
)
|
|
{
|
|
if (IsVerboseLoggingEnabled())
|
|
{
|
|
if (a_pszNameSpace != NULL)
|
|
{
|
|
LogMessage4(L"%s%s:%s", IDS_FRAMEWORKLOGIN, a_pszNameSpace, a_szName);
|
|
}
|
|
else
|
|
{
|
|
LogMessage4(L"%s%s:%s", IDS_FRAMEWORKLOGIN, DEFAULT_NAMESPACE, a_szName);
|
|
}
|
|
}
|
|
|
|
// AddProviderToMap, searches the Map for a match first.
|
|
// If one is found, it does not perform the actual add.
|
|
// Check that the pointers are the same. If they're
|
|
// different, this is what happened.
|
|
|
|
// pProvider doesn't get addref'ed, so no release necessary
|
|
Provider *t_pTestProvider = AddProviderToMap( a_szName, a_pszNameSpace, a_pProvider );
|
|
|
|
if ( t_pTestProvider != a_pProvider )
|
|
{
|
|
// this should never happen
|
|
// a provider should login only once at construction and out at destruction
|
|
// this should coincide with DLLs being loaded and unloaded.
|
|
LogErrorMessage4(L"%s (%s:%s)", IDS_LOGINDISALLOWED, a_pszNameSpace, a_szName);
|
|
ASSERT_BREAK( FALSE );
|
|
}
|
|
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::FrameworkLogoff
|
|
//
|
|
// Static entry point for providers to log out of the framework,
|
|
// this should be called from the provider's dtor so that we release
|
|
// all of our pointers so they don't dangle.
|
|
//
|
|
// Inputs: LPCWSTR& strName - Name of object for map.
|
|
// LPCWSTR pszNameSpace - NameSpace of provider
|
|
//
|
|
// Outputs: None.
|
|
//
|
|
// Returns: usually.
|
|
//
|
|
// Comments: We don't bother removing entries from the namespace map.
|
|
//
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
void CWbemProviderGlue::FrameworkLogoff(
|
|
|
|
LPCWSTR a_pszName,
|
|
LPCWSTR a_pszNamespace
|
|
)
|
|
{
|
|
STRING2LPVOID::iterator mapIter;
|
|
|
|
try
|
|
{
|
|
if (IsVerboseLoggingEnabled())
|
|
{
|
|
LogMessage3(L"%s%s", IDS_FRAMEWORKLOGOFF, a_pszName);
|
|
}
|
|
|
|
BOOL bDone = FALSE;
|
|
CHString strQualifiedName;
|
|
|
|
do
|
|
{
|
|
try
|
|
{
|
|
strQualifiedName = a_pszName;
|
|
bDone = TRUE;
|
|
}
|
|
catch ( CHeap_Exception e_HE )
|
|
{
|
|
// resources could be eventually back
|
|
::Sleep ( 1000 );
|
|
}
|
|
}
|
|
while ( !bDone );
|
|
bDone = FALSE;
|
|
|
|
// If our NameSpace is non-NULL (we use DEFAULT_NAMESPACE then), AND it
|
|
// is not DEFAULT_NAMESPACE, concat the namespace to the provider name
|
|
// so we can differentiate providers across namespaces.
|
|
|
|
if ( (a_pszNamespace != NULL) && (a_pszNamespace[0] != L'\0')
|
|
&& 0 != _wcsicmp(a_pszNamespace, DEFAULT_NAMESPACE ) )
|
|
{
|
|
do
|
|
{
|
|
try
|
|
{
|
|
strQualifiedName += a_pszNamespace;
|
|
bDone = TRUE;
|
|
}
|
|
catch ( CHeap_Exception e_HE )
|
|
{
|
|
// resources could be eventually back
|
|
::Sleep ( 1000 );
|
|
}
|
|
}
|
|
while ( !bDone );
|
|
bDone = FALSE;
|
|
}
|
|
|
|
// Convert characters to upper case before searching for
|
|
// them in the map. Since we convert to upper case when
|
|
// we store the map associations, this effectively makes
|
|
// us case-insensitive.
|
|
|
|
strQualifiedName.MakeUpper();
|
|
|
|
EnterCriticalSectionWait ecs ( &s_csProviderMap );
|
|
LeaveCriticalSectionScope lcs ( &s_csProviderMap );
|
|
|
|
if( ( mapIter = s_providersmap.find( strQualifiedName ) ) != s_providersmap.end() )
|
|
s_providersmap.erase(mapIter);
|
|
else
|
|
ASSERT_BREAK(0 /* did not find provider to log off!*/);
|
|
}
|
|
catch ( ... )
|
|
{
|
|
// we should not be here
|
|
// do not re-throw (called from destructor)
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::GetAllInstances
|
|
//
|
|
// Static entry point for providers to obtain instance lists from
|
|
// other providers.
|
|
//
|
|
// Inputs: LPCWSTR pszProviderName - Name of provider to
|
|
// get list for.
|
|
// TRefPointerCollection<CInstance> *pList - List to fill.
|
|
// LPCWSTR pszNamespace - Namespace of provider.
|
|
//
|
|
// Outputs: None.
|
|
//
|
|
// Returns: HRESULT hr - Status code.
|
|
//
|
|
// Comments: This is an internal entry point, allowing providers
|
|
// to short circuit having to go through WBEM to access
|
|
// data from other providers.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT WINAPI CWbemProviderGlue::GetAllInstances(
|
|
|
|
LPCWSTR pszClassName,
|
|
TRefPointerCollection<CInstance> *pList,
|
|
LPCWSTR pszNamespace, /* = NULL*/
|
|
MethodContext *pMethodContext /* = NULL*/
|
|
)
|
|
{
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
|
|
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::FrameworkTimer);
|
|
|
|
if (pszClassName)
|
|
{
|
|
CHString sQuery;
|
|
|
|
sQuery.Format(L"SELECT * FROM %s where __CLASS = \"%s\"", pszClassName, pszClassName);
|
|
hr = GetInstancesByQuery( sQuery, pList, pMethodContext, pszNamespace);
|
|
}
|
|
else
|
|
{
|
|
hr = WBEM_E_INVALID_PARAMETER;
|
|
}
|
|
|
|
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::ProviderTimer);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::GetAllInstancesAsynch
|
|
//
|
|
// Static entry point for providers to obtain instances from
|
|
// other providers. Note that this is not, strictly speaking,
|
|
// an asynchronous implementation - it does HELP the asynch calls
|
|
// in that it does not build a big list and that the callback allows
|
|
// the provider to respond asynchronously
|
|
//
|
|
// Inputs: LPCWSTR pszProviderName - Name of provider to
|
|
// get instances from.
|
|
//
|
|
// Provider * this is the "this" pointer for the requester
|
|
// LPProviderInstanceCallback callback function to eat the instances provided
|
|
// LPCWSTR pszNamespace - Namespace of provider.
|
|
//
|
|
// Outputs: None.
|
|
//
|
|
// Returns: HRESULT hr - Status code.
|
|
//
|
|
// Comments: This is an internal entry point, allowing providers
|
|
// to short circuit having to go through WBEM to access
|
|
// data from other providers.
|
|
// this puppy shares a lot of code with GetAllInstances, but I
|
|
// can't find a clean way to combine them.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT WINAPI CWbemProviderGlue::GetAllInstancesAsynch(
|
|
|
|
LPCWSTR pszClassName,
|
|
Provider *pRequester,
|
|
LPProviderInstanceCallback pCallback,
|
|
LPCWSTR pszNamespace,
|
|
MethodContext *pMethodContext,
|
|
void *pUserData
|
|
)
|
|
{
|
|
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::FrameworkTimer);
|
|
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
|
|
if (pszClassName)
|
|
{
|
|
CHString sQuery;
|
|
sQuery.Format(L"SELECT * FROM %s where __CLASS = \"%s\"", pszClassName, pszClassName);
|
|
hr = GetInstancesByQueryAsynch( sQuery, pRequester, pCallback, pszNamespace, pMethodContext, pUserData);
|
|
|
|
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::ProviderTimer);
|
|
}
|
|
else
|
|
{
|
|
hr = WBEM_E_INVALID_PARAMETER;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::GetAllDerivedInstances
|
|
//
|
|
// Static entry point for providers to obtain instance lists from
|
|
// other providers. This one will return all instances derived from
|
|
// the base class passed in.
|
|
//
|
|
// Inputs: LPCWSTR pszBaseClassName - Name of base class
|
|
// to get list for.
|
|
// TRefPointerCollection<CInstance> *pList - List to fill.
|
|
// LPCWSTR pszNamespace - Namespace of provider.
|
|
// MethodContext *pMethodContext, // must not be NULL
|
|
//
|
|
// Outputs: None.
|
|
//
|
|
// Returns: HRESULT hr - Status code.
|
|
//
|
|
// Comments: This is an internal entry point, allowing providers
|
|
// to short circuit having to go through WBEM to access
|
|
// data from other providers.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT WINAPI CWbemProviderGlue::GetAllDerivedInstances(
|
|
|
|
LPCWSTR pszBaseClassName,
|
|
TRefPointerCollection<CInstance> *pList,
|
|
MethodContext *pMethodContext,
|
|
LPCWSTR pszNamespace
|
|
)
|
|
{
|
|
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::FrameworkTimer);
|
|
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
|
|
if (pszBaseClassName)
|
|
{
|
|
CHString sQuery;
|
|
sQuery.Format(L"SELECT * FROM %s", pszBaseClassName);
|
|
hr = GetInstancesByQuery( sQuery, pList, pMethodContext, pszNamespace);
|
|
}
|
|
else
|
|
{
|
|
hr = WBEM_E_INVALID_PARAMETER;
|
|
}
|
|
|
|
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::ProviderTimer);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::GetAllDerivedInstancesAsynch
|
|
//
|
|
// Static entry point for providers to obtain instances from
|
|
// other providers. Note that this is not, strictly speaking,
|
|
// an asynchronous implementation - it does HELP the asynch calls
|
|
// in that it does not build a big list and that the callback allows
|
|
// the provider to respond asynchronously
|
|
//
|
|
// Inputs: LPCWSTR pszProviderName - Name of provider to
|
|
// get instances from.
|
|
//
|
|
// Provider* this is the "this" pointer for the requester
|
|
// LPProviderInstanceCallback callback function to eat the instances provided
|
|
// LPCWSTR pszNamespace - Namespace of provider.
|
|
//
|
|
// Outputs: None.
|
|
//
|
|
// Returns: HRESULT hr - Status code.
|
|
//
|
|
// Comments: This is an internal entry point, allowing providers
|
|
// to short circuit having to go through WBEM to access
|
|
// data from other providers.
|
|
// this puppy shares a lot of code with GetAllInstances, but I
|
|
// can't find a clean way to combine them.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT WINAPI CWbemProviderGlue::GetAllDerivedInstancesAsynch(
|
|
|
|
LPCWSTR pszProviderName,
|
|
Provider *pRequester,
|
|
LPProviderInstanceCallback pCallback,
|
|
LPCWSTR pszNamespace,
|
|
MethodContext *pMethodContext,
|
|
void *pUserData
|
|
)
|
|
{
|
|
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::FrameworkTimer);
|
|
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
|
|
if (pszProviderName)
|
|
{
|
|
CHString sQuery;
|
|
sQuery.Format(L"SELECT * FROM %s", pszProviderName);
|
|
hr = GetInstancesByQueryAsynch( sQuery, pRequester, pCallback, pszNamespace, pMethodContext, pUserData);
|
|
}
|
|
else
|
|
{
|
|
hr = WBEM_E_INVALID_PARAMETER;
|
|
}
|
|
|
|
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::ProviderTimer);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::GetInstancesByQuery
|
|
//
|
|
// Static entry point for providers to obtain instance lists from
|
|
// other providers. This one will return all instances matching a query.
|
|
//
|
|
// Inputs: LPCWSTR Query to execute "Select * from win32_foo where bar = "baz""
|
|
// TRefPointerCollection<CInstance> *pList - List to fill.
|
|
// MethodContext *pMethodContext, // must not be NULL
|
|
// LPCWSTR pointer to namespace - may be NULL (means default -- root\cimv2)
|
|
//
|
|
// Outputs: None.
|
|
//
|
|
// Returns: HRESULT hr - Status code.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT WINAPI CWbemProviderGlue::GetInstancesByQuery( LPCWSTR query,
|
|
TRefPointerCollection<CInstance> *pList,
|
|
MethodContext *pMethodContext,
|
|
LPCWSTR pszNamespace /* = NULL*/)
|
|
{
|
|
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::FrameworkTimer);
|
|
if (IsVerboseLoggingEnabled())
|
|
{
|
|
LogMessage3(L"%s (%s)", IDS_GETINSTANCESBYQUERY, query);
|
|
}
|
|
|
|
HRESULT hr = WBEM_E_FAILED;
|
|
|
|
if ( (query != NULL) &&
|
|
(pList != NULL) &&
|
|
(pMethodContext != NULL) )
|
|
{
|
|
IEnumWbemClassObjectPtr pEnum;
|
|
|
|
IWbemContextPtr pWbemContext;
|
|
if (pMethodContext)
|
|
{
|
|
pWbemContext.Attach(pMethodContext->GetIWBEMContext());
|
|
}
|
|
|
|
IWbemServicesPtr piService;
|
|
|
|
// get a service interface
|
|
if (pszNamespace == NULL || pszNamespace[0] == L'\0')
|
|
{
|
|
piService.Attach(GetNamespaceConnection(NULL, pMethodContext));
|
|
}
|
|
else
|
|
{
|
|
piService.Attach(GetNamespaceConnection( pszNamespace, pMethodContext));
|
|
}
|
|
|
|
if ( piService != NULL)
|
|
{
|
|
{
|
|
// Assures that impersonation goes
|
|
// back to the way it was before the
|
|
// call to CIMOM.
|
|
CAutoImpRevert air;
|
|
DWORD dwImpErr = air.LastError();
|
|
if(dwImpErr == ERROR_SUCCESS)
|
|
{
|
|
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::WinMgmtTimer);
|
|
hr = piService->ExecQuery(bstr_t(IDS_WQL), bstr_t(query), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, pWbemContext, &pEnum);
|
|
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::FrameworkTimer);
|
|
}
|
|
else
|
|
{
|
|
LogErrorMessage2(L"Failed to open current thread token for checking impersonation, with error %d", dwImpErr);
|
|
hr = WBEM_E_FAILED;
|
|
}
|
|
}
|
|
|
|
if ( SUCCEEDED( hr ) )
|
|
{
|
|
IWbemClassObjectPtr pObj;
|
|
ULONG nReturned;
|
|
|
|
// author's apology:
|
|
// we loop through, using Next() to get each instance
|
|
// we bail when we get WBEM_S_FALSE because that's the end of the enumeration
|
|
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::WinMgmtTimer);
|
|
for (hr = pEnum->Next(GLUETIMEOUT, 1, &pObj, &nReturned);
|
|
(SUCCEEDED(hr) && (hr != WBEM_S_FALSE) && (hr != WBEM_S_TIMEDOUT) ) ;
|
|
hr = pEnum->Next(GLUETIMEOUT, 1, &pObj, &nReturned))
|
|
{
|
|
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::FrameworkTimer);
|
|
if (pObj != NULL && nReturned)
|
|
{
|
|
CInstancePtr pInstance(new CInstance(pObj, pMethodContext), false);
|
|
|
|
if (pInstance != NULL)
|
|
{
|
|
// Check to see if adding to the list succeeds
|
|
if (!pList->Add(pInstance))
|
|
{
|
|
hr = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::FrameworkTimer);
|
|
|
|
// the Next will return WBEM_S_FALSE when it is done. However, that
|
|
// means that THIS function had no error.
|
|
if (hr == WBEM_S_FALSE)
|
|
{
|
|
hr = WBEM_S_NO_ERROR;
|
|
}
|
|
// fencepost check - the last error might have been access denied
|
|
// but it's okay if we got any instances at all
|
|
else if (hr == WBEM_E_ACCESS_DENIED)
|
|
if (pList->GetSize() > 0)
|
|
hr = WBEM_S_NO_ERROR;
|
|
|
|
|
|
} // IF SUCCEEDED
|
|
}
|
|
else
|
|
LogErrorMessage(IDS_FAILED);
|
|
}
|
|
else
|
|
{
|
|
hr = WBEM_E_INVALID_PARAMETER;
|
|
LogErrorMessage(L"NULL parameter to GetInstancesByQuery");
|
|
ASSERT_BREAK(WBEM_E_INVALID_PARAMETER);
|
|
}
|
|
|
|
if (IsVerboseLoggingEnabled())
|
|
{
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LogMessage3(L"%s (%s) - Succeeded", IDS_GETINSTANCESBYQUERY, query);
|
|
}
|
|
else
|
|
{
|
|
LogMessage4(L"%s (%s) - FAILED (%x)", IDS_GETINSTANCESBYQUERY, query, hr);
|
|
}
|
|
}
|
|
|
|
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::ProviderTimer);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::IsDerivedFrom
|
|
//
|
|
// Static entry point for providers to obtain derivation information
|
|
//
|
|
// Inputs: LPCWSTR pszBaseClassName - Name of base class
|
|
// LPCWSTR pszDerivedClassName - Name of class we're testing
|
|
// MethodContext *pMethodContext
|
|
//
|
|
// Outputs: None.
|
|
//
|
|
// Returns: true iff pszDerivedClassName is derived from pszBaseClassName
|
|
//
|
|
// Comments: This function cannot short circuit, because a derived class may be external
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
bool CWbemProviderGlue::IsDerivedFrom(
|
|
|
|
LPCWSTR pszBaseClassName,
|
|
LPCWSTR pszDerivedClassName,
|
|
MethodContext *pMethodContext,
|
|
LPCWSTR pszNamespace /* = NULL*/
|
|
)
|
|
{
|
|
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::FrameworkTimer);
|
|
|
|
bool bRet = false;
|
|
|
|
if ( (pszBaseClassName != NULL) &&
|
|
(pszDerivedClassName != NULL) &&
|
|
(pMethodContext != NULL) )
|
|
{
|
|
IWbemServicesPtr piService;
|
|
|
|
// get a service interface
|
|
piService.Attach(GetNamespaceConnection( pszNamespace, pMethodContext ));
|
|
|
|
// find the derived class object
|
|
if (piService != NULL)
|
|
{
|
|
IWbemClassObjectPtr pObj;
|
|
IWbemContextPtr pWbemContext;
|
|
if (pMethodContext)
|
|
{
|
|
pWbemContext.Attach(pMethodContext->GetIWBEMContext());
|
|
}
|
|
|
|
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::WinMgmtTimer);
|
|
HRESULT hr = piService->GetObject( bstr_t( pszDerivedClassName ), 0, pWbemContext, &pObj, NULL);
|
|
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::FrameworkTimer);
|
|
|
|
if (SUCCEEDED(hr) && (pObj != NULL))
|
|
{
|
|
// Variant_t handles the VariantInit/VariantClear
|
|
variant_t v;
|
|
|
|
if (SUCCEEDED(pObj->Get((unsigned short *)IDS_DERIVATION, 0, &v, NULL, NULL)))
|
|
{
|
|
BSTR bstrTemp = NULL;
|
|
SAFEARRAY *psa = V_ARRAY(&v);
|
|
LONG uBound;
|
|
SafeArrayGetUBound(psa, 1, &uBound);
|
|
|
|
// if base class is in the list in the derivation, we're true!
|
|
for (LONG i = 0; !bRet && (i <= uBound); i++)
|
|
{
|
|
if (SUCCEEDED(SafeArrayGetElement( psa, &i, &bstrTemp )))
|
|
{
|
|
OnDeleteIf<BSTR,VOID(*)(BSTR),SysFreeString> smartbstrTemp(bstrTemp);
|
|
bRet = (_wcsicmp(pszBaseClassName, bstrTemp) == 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LogErrorMessage(L"NULL parameter to IsDerivedFrom");
|
|
ASSERT_BREAK(WBEM_E_INVALID_PARAMETER);
|
|
}
|
|
|
|
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::ProviderTimer);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::GetEmptyInstance
|
|
//
|
|
// Static entry point for providers to obtain a single empty instance
|
|
// of a provider object.
|
|
//
|
|
// Inputs: LPCWSTR pszProviderName - Name of provider to
|
|
// get list for.
|
|
// LPCWSTR pszNamespace - Namespace of provider.
|
|
//
|
|
// Outputs: CInstance **ppInstance - Pointer to store new
|
|
// pInstance in. Must be Released by
|
|
// caller.
|
|
//
|
|
// Returns: HRESULT hr - Status code.
|
|
//
|
|
// Comments: This is an internal entry point, allowing providers
|
|
// to short circuit having to go through WBEM to access
|
|
// data from other providers.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
// DEPRECATED
|
|
HRESULT WINAPI CWbemProviderGlue::GetEmptyInstance(
|
|
|
|
LPCWSTR pszClassName,
|
|
CInstance **ppInstance,
|
|
LPCWSTR pszNamespace
|
|
)
|
|
{
|
|
ASSERT_BREAK(DEPRECATED);
|
|
|
|
HRESULT hr = WBEM_E_INVALID_CLASS;
|
|
|
|
if ( (pszClassName != NULL) &&
|
|
(ppInstance != NULL) )
|
|
{
|
|
// Search for the class name in our map of providers, we know which
|
|
// namespace we are when we get constructed.
|
|
|
|
// pProvider doesn't get addref'ed, so no release is necessary
|
|
Provider *pProvider = SearchMapForProvider( pszClassName, pszNamespace );
|
|
|
|
if ( NULL != pProvider )
|
|
{
|
|
// Now create an Internal Method Context object, since this function
|
|
// only gets called internal to our DLL. Using a NULL for the
|
|
// list pointer, essentially creates a dummy context so we can
|
|
// do our commit dance as painlessly as possible.
|
|
|
|
InternalMethodContextPtr pContext (new InternalMethodContext( NULL, NULL, NULL ), false);
|
|
|
|
if ( NULL != pContext )
|
|
{
|
|
// Assume things will go wrong like a good liitle paranoiac
|
|
hr = WBEM_E_FAILED;
|
|
|
|
// Before asking for a new instance, we MUST verify that the
|
|
// provider has a valid IMOS pointer. If it does'nt, CreateNewInstance
|
|
// may GPF (this is a safety check we must do because of our
|
|
// little short circuit.
|
|
|
|
// We don't do short circuits anymore.
|
|
// if ( pProvider->ValidateIMOSPointer() )
|
|
{
|
|
// Set the error code appropriately depending on whether or
|
|
// not the Instance gets created correctly.
|
|
|
|
// The instance returned will have been AddRefed, so it will
|
|
// be up to the caller to Release() it.
|
|
|
|
if ( ( *ppInstance = pProvider->CreateNewInstance( pContext ) ) != NULL )
|
|
{
|
|
hr = WBEM_S_NO_ERROR;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = WBEM_E_INVALID_CLASS;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = WBEM_E_INVALID_PARAMETER;
|
|
LogErrorMessage(L"NULL parameter to GetEmptyInstance");
|
|
ASSERT_BREAK(WBEM_E_INVALID_PARAMETER);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::GetEmptyInstance
|
|
//
|
|
// Static entry point for providers to obtain a single empty instance
|
|
// of a provider object. This alternate form makes a call back
|
|
// into WINMGMT.
|
|
//
|
|
// Inputs: MethodContext *Context object for this call
|
|
// LPCWSTR pszProviderName - Name of provider to
|
|
// get instance of.
|
|
// LPCWSTR pszNamespace - Namespace of class.
|
|
//
|
|
// Outputs: CInstance **ppInstance - Pointer to store new
|
|
// pInstance in. Must be Released by
|
|
// caller.
|
|
//
|
|
// Returns: HRESULT hr - Status code.
|
|
//
|
|
// Comments:
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT WINAPI CWbemProviderGlue::GetEmptyInstance(
|
|
|
|
MethodContext *pMethodContext,
|
|
LPCWSTR pszProviderName,
|
|
CInstance **ppOutInstance,
|
|
LPCWSTR a_pszNamespace
|
|
)
|
|
{
|
|
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::FrameworkTimer);
|
|
|
|
HRESULT hr = WBEM_E_FAILED;
|
|
|
|
if ( (pMethodContext != NULL) &&
|
|
(pszProviderName != NULL) &&
|
|
(ppOutInstance != NULL) )
|
|
{
|
|
|
|
CInstancePtr pClassInstance;
|
|
|
|
hr = GetInstanceFromCIMOM(pszProviderName, a_pszNamespace, pMethodContext, &pClassInstance);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IWbemClassObjectPtr pClassObject(pClassInstance->GetClassObjectInterface(), false);
|
|
if (pClassObject != NULL)
|
|
{
|
|
IWbemClassObjectPtr pObj;
|
|
hr = pClassObject->SpawnInstance(0, &pObj);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*ppOutInstance = new CInstance(pObj, pMethodContext);
|
|
if (*ppOutInstance == NULL)
|
|
{
|
|
throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = WBEM_E_FAILED;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = WBEM_E_INVALID_PARAMETER;
|
|
LogErrorMessage(L"NULL parameter to GetEmptyInstance");
|
|
ASSERT_BREAK(WBEM_E_INVALID_PARAMETER);
|
|
}
|
|
|
|
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::ProviderTimer);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::FillInstance
|
|
//
|
|
// Static entry point for providers to pass us an instance with
|
|
// key data filled out, which we will use to locate the correct
|
|
// provider and ask it to fill out completely.
|
|
//
|
|
// Inputs: CInstance *pInstance - Instance to fill out.
|
|
// LPCWSTR pszNamespace - Namespace for provider.
|
|
//
|
|
// Outputs: None.
|
|
//
|
|
// Returns: HRESULT hr - Status code.
|
|
//
|
|
// Comments: This is an internal entry point, allowing providers
|
|
// to short circuit having to go through WBEM to access
|
|
// data from other providers.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
// DEPRECATED!
|
|
HRESULT WINAPI CWbemProviderGlue::FillInstance(
|
|
|
|
CInstance *pInstance,
|
|
LPCWSTR pszNamespace /*= NULL*/
|
|
)
|
|
{
|
|
ASSERT_BREAK(DEPRECATED);
|
|
|
|
HRESULT hr = WBEM_E_FAILED;
|
|
|
|
if (pInstance != NULL)
|
|
{
|
|
// Check that we have an instance pointer, then pull out the
|
|
// class name and name space. From there we can find the
|
|
// appropriate provider and ask it to get the object.
|
|
|
|
if ( NULL != pInstance )
|
|
{
|
|
CHString strProviderName;
|
|
pInstance->GetCHString( IDS_CLASS, strProviderName );
|
|
|
|
// Search for the class name in our map of providers, we know which
|
|
// namespace we are when we get constructed.
|
|
|
|
// pProvider is not addref'ed, so no release is necessary
|
|
Provider *pProvider = SearchMapForProvider( strProviderName, pszNamespace );
|
|
|
|
if ( NULL != pProvider )
|
|
{
|
|
// Pass the pInstance off to the provider and let it take care
|
|
// of obtaining the correct values.
|
|
|
|
hr = pProvider->GetObject( pInstance );
|
|
}
|
|
else
|
|
{
|
|
hr = WBEM_E_INVALID_CLASS;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = WBEM_E_INVALID_PARAMETER;
|
|
LogErrorMessage(L"NULL parameter to FillInstance");
|
|
ASSERT_BREAK(WBEM_E_INVALID_PARAMETER);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::FillInstance
|
|
//
|
|
// Static entry point for providers to pass us an instance with
|
|
// key data filled out, use to make a call back into winmgmt.
|
|
//
|
|
// Inputs: MethodContext *Context object for this call
|
|
// CInstance *pInstance - Instance to fill out.
|
|
//
|
|
// Outputs: None.
|
|
//
|
|
// Returns: HRESULT hr - Status code.
|
|
//
|
|
// Comments:
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT WINAPI CWbemProviderGlue::FillInstance(
|
|
|
|
MethodContext *pMethodContext,
|
|
CInstance *pInstance
|
|
)
|
|
{
|
|
ASSERT_BREAK(DEPRECATED);
|
|
|
|
HRESULT hr = WBEM_E_FAILED;
|
|
|
|
if ( (pMethodContext != NULL) &&
|
|
(pInstance != NULL) )
|
|
{
|
|
// Check that we have an instance pointer, then pull out the path
|
|
// and send it to cimom.
|
|
CHString strPathName;
|
|
|
|
pInstance->GetCHString( L"__RELPATH", strPathName );
|
|
hr = GetInstanceByPath(strPathName, &pInstance, pMethodContext);
|
|
}
|
|
else
|
|
{
|
|
hr = WBEM_E_INVALID_PARAMETER;
|
|
LogErrorMessage(L"NULL parameter to FillInstance");
|
|
ASSERT_BREAK(WBEM_E_INVALID_PARAMETER);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::GetInstanceKeysByPath
|
|
//
|
|
// Static entry point for providers to pass us an instance path
|
|
// to retrieve. This class uses per-property gets to request
|
|
// only the keys on the object we are retrieving.
|
|
//
|
|
// Inputs: pszInstancePath Object path to retrieve
|
|
// CInstance *pInstance - Instance to fill out.
|
|
// MethodContext *Context object for this call
|
|
//
|
|
// Outputs: None
|
|
//
|
|
// Returns: HRESULT hr - Status code.
|
|
//
|
|
// Comments:
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT WINAPI CWbemProviderGlue::GetInstanceKeysByPath(
|
|
|
|
LPCWSTR pszInstancePath,
|
|
CInstance **ppInstance,
|
|
MethodContext *pMethodContext
|
|
)
|
|
{
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
|
|
if ( (pMethodContext != NULL) &&
|
|
(pszInstancePath != NULL) &&
|
|
(ppInstance != NULL) )
|
|
{
|
|
|
|
IWbemContextPtr pWbemContext(pMethodContext->GetIWBEMContext(), false);
|
|
|
|
// We need to have a real context object, not an internal method context
|
|
if (pWbemContext != NULL)
|
|
{
|
|
VARIANT vValue;
|
|
V_VT(&vValue) = VT_BOOL;
|
|
V_BOOL(&vValue) = VARIANT_TRUE;
|
|
|
|
// Set the appropriate properties on the context object
|
|
if ( (SUCCEEDED(hr = pWbemContext->SetValue(L"__GET_EXTENSIONS", 0L, &vValue))) &&
|
|
(SUCCEEDED(hr = pWbemContext->SetValue(L"__GET_EXT_KEYS_ONLY", 0L, &vValue))) &&
|
|
(SUCCEEDED(hr = pWbemContext->SetValue(L"__GET_EXT_CLIENT_REQUEST", 0L, &vValue))))
|
|
{
|
|
LogMessage2(L"GetInstanceKeysByPath: %s", pszInstancePath);
|
|
hr = GetInstanceByPath(pszInstancePath, ppInstance, pMethodContext);
|
|
|
|
V_BOOL(&vValue) = VARIANT_FALSE;
|
|
pWbemContext->SetValue(L"__GET_EXTENSIONS", 0L, &vValue);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ASSERT_BREAK(FALSE);
|
|
LogErrorMessage(L"Can't use InternalMethodContext to GetInstanceKeysByPath");
|
|
hr = WBEM_E_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = WBEM_E_INVALID_PARAMETER;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::GetInstancePropertiesByPath
|
|
//
|
|
// Static entry point for providers to pass us an instance path
|
|
// to retrieve. This class uses per-property gets to request
|
|
// only the properties specified in the array.
|
|
//
|
|
// Inputs: pszInstancePath Object path to retrieve
|
|
// CInstance *pInstance - Instance to fill out.
|
|
// MethodContext *Context object for this call
|
|
// csaProperties Properties to request
|
|
//
|
|
// Outputs: None
|
|
//
|
|
// Returns: HRESULT hr - Status code.
|
|
//
|
|
// Comments:
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT WINAPI CWbemProviderGlue::GetInstancePropertiesByPath(
|
|
|
|
LPCWSTR pszInstancePath,
|
|
CInstance **ppInstance,
|
|
MethodContext *pMethodContext,
|
|
CHStringArray &csaProperties
|
|
)
|
|
{
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
|
|
if ( (pMethodContext != NULL) &&
|
|
(pszInstancePath != NULL) &&
|
|
(ppInstance != NULL) )
|
|
{
|
|
|
|
IWbemContextPtr pWbemContext(pMethodContext->GetIWBEMContext(), false);
|
|
|
|
// We need to have a real context object, not an internal method context
|
|
if (pWbemContext != NULL)
|
|
{
|
|
variant_t vValue;
|
|
V_VT(&vValue) = VT_BOOL;
|
|
V_BOOL(&vValue) = VARIANT_TRUE;
|
|
|
|
// First set the value that says we are using Get extensions
|
|
if ((SUCCEEDED(hr = pWbemContext->SetValue(L"__GET_EXTENSIONS", 0L, &vValue))) &&
|
|
(SUCCEEDED(hr = pWbemContext->SetValue(L"__GET_EXT_CLIENT_REQUEST", 0L, &vValue))) )
|
|
{
|
|
// Delete any unneeded properties
|
|
pWbemContext->DeleteValue(L"__GET_EXT_KEYS_ONLY", 0L);
|
|
|
|
// Now build the array of properties
|
|
SAFEARRAYBOUND rgsabound [ 1 ] ;
|
|
|
|
rgsabound[0].cElements = csaProperties.GetSize() ;
|
|
rgsabound[0].lLbound = 0 ;
|
|
V_ARRAY(&vValue) = SafeArrayCreate ( VT_BSTR, 1, rgsabound ) ;
|
|
if ( V_ARRAY(&vValue) )
|
|
{
|
|
V_VT(&vValue) = VT_BSTR | VT_ARRAY;
|
|
|
|
for (long x=0; x < csaProperties.GetSize(); x++)
|
|
{
|
|
bstr_t bstrProp = csaProperties[x];
|
|
|
|
SafeArrayPutElement(
|
|
V_ARRAY(&vValue),
|
|
&x,
|
|
(LPVOID) (BSTR) bstrProp);
|
|
}
|
|
|
|
// Put the array into the context object
|
|
if (SUCCEEDED(hr = pWbemContext->SetValue(L"__GET_EXT_PROPERTIES", 0L, &vValue)))
|
|
{
|
|
LogMessage2(L"GetInstancePropertiesByPath: %s", pszInstancePath);
|
|
// Make the call
|
|
hr = GetInstanceByPath(pszInstancePath, ppInstance, pMethodContext);
|
|
|
|
vValue.Clear();
|
|
V_VT(&vValue) = VT_BOOL;
|
|
V_BOOL(&vValue) = VARIANT_FALSE;
|
|
pWbemContext->SetValue(L"__GET_EXTENSIONS", 0L, &vValue);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ASSERT_BREAK(FALSE);
|
|
LogErrorMessage(L"Can't use InternalMethodContext to GetInstanceKeysByPath");
|
|
hr = WBEM_E_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = WBEM_E_INVALID_PARAMETER;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::GetInstanceByPath
|
|
//
|
|
// Static entry point for providers to obtain a single empty instance
|
|
// of a provider object.
|
|
//
|
|
// Inputs: LPCWSTR pszInstancePath - Path to Object. This
|
|
// MUST be a full path,
|
|
// MethodContext *pMethodContext - Method Context containing
|
|
// (hopefully) the WbemContext we need
|
|
// to propogate.
|
|
//
|
|
// Outputs: CInstance** ppInstance - Pointer to store new
|
|
// pInstance in. Must be Released by
|
|
// caller.
|
|
//
|
|
// Returns: HRESULT hr - Status code.
|
|
//
|
|
// Comments: This is an internal entry point, allowing providers
|
|
// to short circuit having to go through WBEM to access
|
|
// data from other providers.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT WINAPI CWbemProviderGlue::GetInstanceByPath(
|
|
|
|
LPCWSTR pszInstancePath,
|
|
CInstance **ppInstance,
|
|
MethodContext *pMethodContext /* = NULL */
|
|
)
|
|
{
|
|
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::FrameworkTimer);
|
|
|
|
HRESULT hr = WBEM_E_FAILED;
|
|
|
|
if ( (pszInstancePath != NULL) &&
|
|
(ppInstance != NULL) )
|
|
{
|
|
CHString strComputerName;
|
|
GetComputerName( strComputerName );
|
|
|
|
DWORD dwError = ::GetLastError ();
|
|
if ( ERROR_SUCCESS != dwError )
|
|
{
|
|
// For this revision, we DO NOT support getting paths that are not local.
|
|
// This is because if the machine name is anything other than the local
|
|
// one, we run the risk of freezing while CIMOM goes out and tries to find
|
|
// the machine (up to around 5 minutes according to his Levness.
|
|
|
|
ParsedObjectPath *pParsedPath = NULL;
|
|
CObjectPathParser objpathParser;
|
|
|
|
// Parse the object path passed to us by CIMOM
|
|
// ==========================================
|
|
int nStatus = objpathParser.Parse( pszInstancePath, &pParsedPath );
|
|
|
|
if ( 0 == nStatus )
|
|
{
|
|
//
|
|
// smart free for pParsedPath
|
|
//
|
|
OnDeleteObjIf < ParsedObjectPath*, CObjectPathParser, void ( CObjectPathParser:: * ) ( ParsedObjectPath* ) , &CObjectPathParser::Free > SmartFree ( &objpathParser, pParsedPath ) ;
|
|
|
|
// Machine names MUST match. Null indicates no machine name specified.
|
|
|
|
if (( pParsedPath->m_pServer == NULL) ||
|
|
( strComputerName.CompareNoCase( pParsedPath->m_pServer ) == 0 ) ||
|
|
( wcscmp(pParsedPath->m_pServer, L".") == 0 )
|
|
)
|
|
{
|
|
// Now try to find the provider based on the class name
|
|
CHString strNamespace;
|
|
|
|
// Pull out the name space parts, and concatenate them using a '\\'
|
|
// character. e.g. root\default.
|
|
|
|
for ( DWORD dwCtr = 0; dwCtr < pParsedPath->m_dwNumNamespaces; dwCtr++ )
|
|
{
|
|
if ( dwCtr != 0 )
|
|
{
|
|
strNamespace += L"\\";
|
|
}
|
|
|
|
strNamespace += pParsedPath->m_paNamespaces[dwCtr];
|
|
}
|
|
|
|
// We need to propogate the Wbem Context if we are going out
|
|
// to CIMOM!
|
|
|
|
IWbemContextPtr pWbemContext;
|
|
CWbemProviderGlue *pGlue = NULL;
|
|
|
|
if ( NULL != pMethodContext )
|
|
{
|
|
pWbemContext.Attach(pMethodContext->GetIWBEMContext());
|
|
pGlue = pMethodContext->GetProviderGlue();
|
|
}
|
|
else
|
|
{
|
|
ASSERT_BREAK(DEPRECATED);
|
|
}
|
|
|
|
InternalMethodContextPtr pInternalContext (
|
|
new InternalMethodContext(
|
|
NULL,
|
|
pWbemContext,
|
|
pGlue), false);
|
|
|
|
if ( NULL != pInternalContext )
|
|
{
|
|
hr = GetInstanceFromCIMOM( pszInstancePath, strNamespace, pInternalContext, ppInstance );
|
|
}
|
|
else
|
|
{
|
|
throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
|
|
|
|
}
|
|
|
|
} // IF Machine Names MATCH
|
|
else
|
|
{
|
|
hr = WBEM_E_INVALID_PARAMETER; // INVALID MACHINE NAME
|
|
}
|
|
|
|
} // IF nStatus == 0
|
|
else
|
|
{
|
|
hr = WBEM_E_INVALID_OBJECT_PATH;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// this could be access denied from GetComputeName
|
|
if ( ERROR_ACCESS_DENIED == dwError )
|
|
{
|
|
hr = WBEM_E_ACCESS_DENIED;
|
|
}
|
|
else
|
|
{
|
|
// it is WBEM_E_FAILED
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = WBEM_E_INVALID_PARAMETER;
|
|
LogErrorMessage(L"NULL parameter to GetInstanceByPath");
|
|
ASSERT_BREAK(WBEM_E_INVALID_PARAMETER);
|
|
}
|
|
|
|
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::ProviderTimer);
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::GetInstanceFromCIMOM
|
|
//
|
|
// Static entry point for providers to obtain a single instance
|
|
// of a WBEM Object. obtaining said object from CIMOM.
|
|
//
|
|
// Inputs: LPCWSTR pszInstancePath - Path to Object. This
|
|
// MUST be a full path,
|
|
// LPCWSTR pszNameSpace - NameSpace of Object.
|
|
// MethodContext *pMethodContext - Method Context
|
|
//
|
|
// Outputs: CInstance **ppInstance - Pointer to store new
|
|
// pInstance in. Must be Released by
|
|
// caller.
|
|
//
|
|
// Returns: HRESULT hr - Status code.
|
|
// will return WBEM_E_INVALID_NAMESPACE if it's not a namespace we support
|
|
// (might otherwise be valid, but not so far as WE are concerned).
|
|
//
|
|
// Comments: This is an internal entry point, allowing providers
|
|
// that failed the short circuit to be propogated
|
|
// by calling into CIMOM.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT WINAPI CWbemProviderGlue::GetInstanceFromCIMOM(
|
|
|
|
LPCWSTR pszInstancePath,
|
|
LPCWSTR pszNamespace,
|
|
MethodContext *pMethodContext,
|
|
CInstance **ppInstance
|
|
)
|
|
{
|
|
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::FrameworkTimer);
|
|
HRESULT hr = WBEM_E_FAILED;
|
|
|
|
if (IsVerboseLoggingEnabled())
|
|
{
|
|
LogMessage3(L"%s (%s)", IDS_INSTANCEFROMCIMOM, pszInstancePath);
|
|
}
|
|
|
|
// We need to propogate the Wbem Context (if any) that was passed to
|
|
// us by CIMOM.
|
|
IWbemContextPtr pWbemContext;
|
|
|
|
if ( NULL != pMethodContext )
|
|
{
|
|
pWbemContext.Attach(pMethodContext->GetIWBEMContext());
|
|
}
|
|
else
|
|
{
|
|
ASSERT_BREAK(DEPRECATED);
|
|
}
|
|
|
|
// If we failed to find the provider, try using CIMOM to do our
|
|
// dirty work for us.
|
|
|
|
IWbemServicesPtr piService;
|
|
IWbemClassObjectPtr piObject;
|
|
|
|
// get a service interface
|
|
if ( (pszNamespace == NULL) || (pszNamespace[0] == L'\0' ))
|
|
{
|
|
piService.Attach(GetNamespaceConnection(NULL, pMethodContext));
|
|
}
|
|
else
|
|
{
|
|
piService.Attach(GetNamespaceConnection( pszNamespace, pMethodContext ));
|
|
}
|
|
|
|
if ( NULL != piService )
|
|
{
|
|
|
|
// No go out to CIMOM to get the object, if this succeeds, new an
|
|
// instance and store everything internally.
|
|
{
|
|
// Assures that impersonation goes
|
|
// back to the way it was before the
|
|
// call to CIMOM.
|
|
CAutoImpRevert air;
|
|
DWORD dwImpErr = air.LastError();
|
|
|
|
if(dwImpErr == ERROR_SUCCESS)
|
|
{
|
|
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::WinMgmtTimer);
|
|
hr = piService->GetObject( bstr_t(pszInstancePath), 0, pWbemContext, &piObject, NULL );
|
|
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::FrameworkTimer);
|
|
}
|
|
else
|
|
{
|
|
LogErrorMessage2(L"Failed to open current thread token for checking impersonation, with error %d", dwImpErr);
|
|
hr = WBEM_E_FAILED;
|
|
}
|
|
}
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
*ppInstance = new CInstance( piObject, pMethodContext );
|
|
if (*ppInstance == NULL)
|
|
{
|
|
throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
|
|
}
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LogErrorMessage(IDS_FAILED);
|
|
hr = WBEM_E_INVALID_NAMESPACE;
|
|
}
|
|
|
|
if (IsVerboseLoggingEnabled())
|
|
{
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LogMessage3(L"%s (%s) - Succeeded", IDS_INSTANCEFROMCIMOM, pszInstancePath);
|
|
}
|
|
else
|
|
{
|
|
LogMessage4(L"%s (%s) - FAILED (%x)", IDS_INSTANCEFROMCIMOM, pszInstancePath, hr);
|
|
}
|
|
}
|
|
|
|
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::ProviderTimer);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::SearchMapForProvider
|
|
//
|
|
// Searches our Provider map for a match against the supplied
|
|
// provider name/NameSpace combination
|
|
//
|
|
// Inputs: const LPCWSTR& strName - Provider Name to find.
|
|
// const LPCWSTR& strNamespace - Provider's Namespace
|
|
//
|
|
// Outputs: None.
|
|
//
|
|
// Returns: Provider *pointer to a provider that was given to
|
|
// us by a call to FrameworkLogin.
|
|
//
|
|
// Comments: None.
|
|
//
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
Provider *CWbemProviderGlue::SearchMapForProvider(
|
|
|
|
LPCWSTR a_pszProviderName,
|
|
LPCWSTR a_pszNamespace
|
|
)
|
|
{
|
|
Provider *pProvider = NULL;
|
|
STRING2LPVOID::iterator mapIter;
|
|
|
|
// If our NameSpace is non-NULL (we use DEFAULT_NAMEPSACE then), AND it
|
|
// is not DEFAULT_NAMESPACE, concat the namespace to the provider name
|
|
// so we can differentiate providers across namespaces.
|
|
|
|
CHString strQualifiedName( a_pszProviderName );
|
|
CHString strLocNamespace( a_pszNamespace );
|
|
|
|
if ( !strLocNamespace.IsEmpty()
|
|
&& 0 != strLocNamespace.CompareNoCase( DEFAULT_NAMESPACE ) )
|
|
{
|
|
|
|
// Convert the / characters to \ for comparison
|
|
WCHAR *pszBuff;
|
|
pszBuff = strLocNamespace.GetBuffer(0);
|
|
while ((pszBuff = wcschr(pszBuff, '/')) != NULL)
|
|
{
|
|
*pszBuff = '\\';
|
|
}
|
|
strLocNamespace.ReleaseBuffer();
|
|
|
|
strQualifiedName += strLocNamespace;
|
|
}
|
|
|
|
// Convert characters to upper case before searching for
|
|
// them in the map. Since we convert to upper case when
|
|
// we store the map associations, this effectively makes
|
|
// us case-insensitive.
|
|
|
|
strQualifiedName.MakeUpper();
|
|
|
|
// Protect the map while we're inside this
|
|
|
|
LockProviderMap();
|
|
OnDelete0 < void (__stdcall *)(void), CWbemProviderGlue::UnlockProviderMap> SmartUnlockProviderMap ;
|
|
|
|
if( ( mapIter = s_providersmap.find( strQualifiedName ) ) != s_providersmap.end() )
|
|
{
|
|
pProvider = (Provider*) (*mapIter).second;
|
|
}
|
|
|
|
return pProvider;
|
|
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::AddProviderToMap
|
|
//
|
|
// Adds a provider to our map. Searches the map first, and if it's
|
|
// not in it, adds it to the map.
|
|
//
|
|
// Inputs: const LPCWSTR strName - Provider Name to Add.
|
|
// const LPCWSTR strNamespace - Namespace for provider.
|
|
// Provider *pProvider - Provider to add to map.
|
|
//
|
|
// Outputs: None.
|
|
//
|
|
// Returns: Provider *pointer to a provider in the map (may
|
|
// be different from the supplied one)
|
|
//
|
|
// Comments: None.
|
|
//
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
Provider *CWbemProviderGlue::AddProviderToMap(
|
|
|
|
LPCWSTR a_szProviderName,
|
|
LPCWSTR a_pszNamespace,
|
|
Provider *a_pProvider
|
|
)
|
|
{
|
|
STRING2LPVOID::iterator mapIter;
|
|
|
|
// If our NameSpace is non-NULL (we use DEFAULT_NAMEPSACE then), AND it
|
|
// is not DEFAULT_NAMESPACE, concat the namespace to the provider name
|
|
// so we can differentiate providers across namespaces.
|
|
|
|
CHString strQualifiedName( a_szProviderName );
|
|
|
|
if ( ( a_pszNamespace != NULL) && (a_pszNamespace[0] != L'\0')
|
|
&& (0 != _wcsicmp(a_pszNamespace, DEFAULT_NAMESPACE )) )
|
|
{
|
|
strQualifiedName += a_pszNamespace;
|
|
}
|
|
|
|
// Convert characters to upper case before searching for
|
|
// them in the map. Since we convert to upper case when
|
|
// we store the map associations, this effectively makes
|
|
// us case-insensitive.
|
|
|
|
strQualifiedName.MakeUpper();
|
|
|
|
// Protect the map while we're inside this
|
|
|
|
Provider *pReturnProvider = NULL;
|
|
LockProviderMap();
|
|
OnDelete0 < void (__stdcall *)(void), CWbemProviderGlue::UnlockProviderMap> SmartUnlockProviderMap ;
|
|
|
|
// First check if we've already got a provider.
|
|
if( ( mapIter = s_providersmap.find( strQualifiedName ) ) != s_providersmap.end() )
|
|
{
|
|
pReturnProvider = (Provider*) (*mapIter).second;
|
|
|
|
//delete it, we're gonna update it shortly
|
|
s_providersmap.erase(mapIter);
|
|
}
|
|
|
|
if ( NULL == pReturnProvider )
|
|
{
|
|
pReturnProvider = a_pProvider;
|
|
}
|
|
|
|
//add in the newly logged in provider
|
|
s_providersmap[strQualifiedName] = (LPVOID) a_pProvider;
|
|
|
|
return pReturnProvider;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWbemProviderGlue::GetComputerName( CHString& strComputerName )
|
|
{
|
|
// Fill the supplied CHString with the local machine name
|
|
DWORD dwBufferLength = MAX_COMPUTERNAME_LENGTH + 1;
|
|
|
|
FRGetComputerName(strComputerName.GetBuffer( dwBufferLength ), &dwBufferLength);
|
|
strComputerName.ReleaseBuffer();
|
|
|
|
if (strComputerName.IsEmpty())
|
|
{
|
|
strComputerName = L"DEFAULT";
|
|
}
|
|
}
|
|
|
|
BOOL CWbemProviderGlue::FrameworkLoginDLL(LPCWSTR a_pszName)
|
|
{
|
|
return CWbemProviderGlue::FrameworkLoginDLL(a_pszName, NULL);
|
|
}
|
|
|
|
BOOL CWbemProviderGlue::FrameworkLogoffDLL(LPCWSTR a_pszNname)
|
|
{
|
|
return CWbemProviderGlue::FrameworkLogoffDLL(a_pszNname, NULL);
|
|
}
|
|
|
|
void CWbemProviderGlue::IncrementObjectCount(void)
|
|
{
|
|
InterlockedIncrement(&s_lObjects);
|
|
if (IsVerboseLoggingEnabled())
|
|
{
|
|
LogMessage2(L"CWbemProviderGlue::IncrementObjectCount. Count is (approx) %d", s_lObjects);
|
|
}
|
|
}
|
|
|
|
LONG CWbemProviderGlue::DecrementObjectCount(void)
|
|
{
|
|
LONG lRet = InterlockedDecrement(&s_lObjects);
|
|
if (IsVerboseLoggingEnabled())
|
|
{
|
|
LogMessage2(L"CWbemProviderGlue::DecrementObjectCount. Count is (approx) %d", s_lObjects);
|
|
}
|
|
|
|
return lRet;
|
|
}
|
|
|
|
// checks impersonation level
|
|
// impersonates client if allowed
|
|
HRESULT WINAPI CWbemProviderGlue::CheckImpersonationLevel()
|
|
{
|
|
HRESULT hr = WBEM_E_ACCESS_DENIED;
|
|
|
|
if (CWbemProviderGlue::GetPlatform() == VER_PLATFORM_WIN32_NT)
|
|
{
|
|
HRESULT hRes = WbemCoImpersonateClient();
|
|
if (SUCCEEDED(hRes)) // From cominit.cpp - needed for nt3.51
|
|
{
|
|
// Now, let's check the impersonation level. First, get the thread token
|
|
HANDLE hThreadTok;
|
|
DWORD dwImp, dwBytesReturned;
|
|
|
|
if (!OpenThreadToken(
|
|
GetCurrentThread(),
|
|
TOKEN_QUERY,
|
|
TRUE,
|
|
&hThreadTok
|
|
))
|
|
{
|
|
DWORD dwLastError = GetLastError();
|
|
|
|
if (dwLastError == ERROR_NO_TOKEN)
|
|
{
|
|
// If the CoImpersonate works, but the OpenThreadToken fails due to ERROR_NO_TOKEN, we
|
|
// are running under the process token (either local system, or if we are running
|
|
// with /exe, the rights of the logged in user). In either case, impersonation rights
|
|
// don't apply. We have the full rights of that user.
|
|
|
|
hr = WBEM_S_NO_ERROR;
|
|
}
|
|
else
|
|
{
|
|
// If we failed to get the thread token for any other reason, log an error.
|
|
LogErrorMessage2(L"Impersonation failure - OpenThreadToken failed (0x%x)", dwLastError);
|
|
hr = WBEM_E_ACCESS_DENIED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// We really do have a thread token, so let's retrieve its level
|
|
|
|
if (GetTokenInformation(
|
|
hThreadTok,
|
|
TokenImpersonationLevel,
|
|
&dwImp,
|
|
sizeof(DWORD),
|
|
&dwBytesReturned
|
|
))
|
|
{
|
|
// Is the impersonation level Impersonate?
|
|
if ((dwImp == SecurityImpersonation) || (dwImp == SecurityDelegation))
|
|
{
|
|
hr = WBEM_S_NO_ERROR;
|
|
}
|
|
else
|
|
{
|
|
hr = WBEM_E_ACCESS_DENIED;
|
|
LogErrorMessage3(L"%s Level(%d)", IDS_ImpersonationFailed, dwImp);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = WBEM_E_FAILED;
|
|
LogErrorMessage3(L"%s Token(%d)", IDS_ImpersonationFailed, GetLastError());
|
|
}
|
|
|
|
// Done with this handle
|
|
CloseHandle(hThreadTok);
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
WbemCoRevertToSelf();
|
|
}
|
|
}
|
|
else if (hRes == E_NOTIMPL)
|
|
{
|
|
// On 3.51 or vanilla 95, this call is not implemented, we should work anyway
|
|
hr = WBEM_S_NO_ERROR;
|
|
}
|
|
else
|
|
{
|
|
LogErrorMessage3(L"%s CoImpersonate(%d)", IDS_ImpersonationFailed, hRes);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// let win9X in...
|
|
hr = WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
if (IsVerboseLoggingEnabled())
|
|
{
|
|
WCHAR wszName[UNLEN + DNLEN + 1 + 1]; // domain + \ + name + null
|
|
DWORD dwLen = UNLEN + DNLEN + 1 + 1;
|
|
|
|
if (GetUserNameEx(NameSamCompatible, wszName, &dwLen))
|
|
{
|
|
LogMessage2(L"Impersonation running as: %s", wszName);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::GetInstancesByQueryAsynch
|
|
//
|
|
// Static entry point for providers to obtain instances from
|
|
// other providers. Note that this is not, strictly speaking,
|
|
// an asynchronous implementation - it does HELP the asynch calls
|
|
// in that it does not build a big list and that the callback allows
|
|
// the provider to respond asynchronously
|
|
//
|
|
// Inputs: LPCWSTR Query to execute "Select * from win32_foo where bar = "baz""
|
|
// Provider * this is the "this" pointer for the requester
|
|
// LPProviderInstanceCallback callback function to eat the instances provided
|
|
// LPCWSTR pszNamespace - Namespace of provider.
|
|
//
|
|
// Outputs: None.
|
|
//
|
|
// Returns: HRESULT hr - Status code.
|
|
//
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT WINAPI CWbemProviderGlue::GetInstancesByQueryAsynch(
|
|
|
|
LPCWSTR query,
|
|
Provider *pRequester,
|
|
LPProviderInstanceCallback pCallback,
|
|
LPCWSTR pszNamespace,
|
|
MethodContext *pMethodContext,
|
|
void *pUserData
|
|
)
|
|
{
|
|
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::FrameworkTimer);
|
|
if (IsVerboseLoggingEnabled())
|
|
{
|
|
LogMessage2(L"GetInstancesByQueryAsynch (%s)", query);
|
|
}
|
|
|
|
HRESULT hr = WBEM_E_FAILED;
|
|
|
|
if ( (query != NULL) &&
|
|
(pRequester != NULL) &&
|
|
(pCallback != NULL) &&
|
|
(pMethodContext != NULL) )
|
|
{
|
|
|
|
// We need to propogate the WBEM context...ESPECIALLY...if we are going out
|
|
// to CIMOM.
|
|
|
|
IWbemContextPtr pWbemContext;
|
|
if (pMethodContext)
|
|
{
|
|
pWbemContext.Attach(pMethodContext->GetIWBEMContext());
|
|
}
|
|
else
|
|
{
|
|
ASSERT_BREAK(DEPRECATED);
|
|
}
|
|
|
|
// Now create an Internal Method Context object, since this function
|
|
// only gets called internal to our DLLs
|
|
InternalMethodContextAsynchPtr pInternalContext (new InternalMethodContextAsynch(pRequester,
|
|
pCallback,
|
|
pWbemContext,
|
|
pMethodContext,
|
|
pUserData), false);
|
|
|
|
if ( NULL != pInternalContext )
|
|
{
|
|
// using CIMOM to do our dirty work for us.
|
|
IWbemServicesPtr piService;
|
|
|
|
// get a service interface
|
|
if (pszNamespace == NULL || pszNamespace[0] == L'\0')
|
|
{
|
|
piService.Attach(GetNamespaceConnection(NULL, pMethodContext));
|
|
}
|
|
else
|
|
{
|
|
piService.Attach(GetNamespaceConnection( pszNamespace, pMethodContext ));
|
|
}
|
|
|
|
if ( NULL != piService )
|
|
{
|
|
IEnumWbemClassObjectPtr pEnum;
|
|
{
|
|
// Assures that impersonation goes
|
|
// back to the way it was before the
|
|
// call to CIMOM.
|
|
CAutoImpRevert air;
|
|
DWORD dwImpErr = air.LastError();
|
|
|
|
if(dwImpErr == ERROR_SUCCESS)
|
|
{
|
|
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::WinMgmtTimer);
|
|
hr = piService->ExecQuery(bstr_t(IDS_WQL),
|
|
bstr_t(query),
|
|
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
|
|
pWbemContext,
|
|
&pEnum);
|
|
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::FrameworkTimer);
|
|
}
|
|
else
|
|
{
|
|
LogErrorMessage2(L"Failed to open current thread token for checking impersonation, with error %d", dwImpErr);
|
|
hr = WBEM_E_FAILED;
|
|
}
|
|
}
|
|
|
|
if ( SUCCEEDED( hr ) )
|
|
{
|
|
IWbemClassObjectPtr pObj;
|
|
ULONG nReturned;
|
|
|
|
// we retrieve all instances of this class and it's children. Note that
|
|
// the next returns WBEM_S_FALSE at the end which PASSES the SUCCEEDED()
|
|
// test, but fails the pObj test.
|
|
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::WinMgmtTimer);
|
|
while (SUCCEEDED(hr) && SUCCEEDED(hr = pEnum->Next(GLUETIMEOUT, 1, &pObj, &nReturned)) && (pObj != NULL))
|
|
{
|
|
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::FrameworkTimer);
|
|
CInstancePtr pInstance(new CInstance(pObj, pMethodContext), false);
|
|
if (pInstance != NULL)
|
|
{
|
|
// For reasons quite beyond me, InternalContext::Commit doesn't
|
|
// release, but external does. Note that the smartptr is doing
|
|
// the release here.
|
|
hr = pInternalContext->Commit(pInstance);
|
|
}
|
|
else
|
|
{
|
|
throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
|
|
}
|
|
}
|
|
|
|
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::FrameworkTimer);
|
|
|
|
// the Next will return WBEM_S_FALSE when it is done. However, that
|
|
// means that THIS function had no error.
|
|
if (hr == WBEM_S_FALSE)
|
|
{
|
|
hr = WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
} // IF SUCCEEDED
|
|
}
|
|
else
|
|
{
|
|
LogErrorMessage(IDS_FAILED);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = WBEM_E_INVALID_PARAMETER;
|
|
LogErrorMessage(L"NULL parameter to GetInstancesByQueryAsynch");
|
|
ASSERT_BREAK(WBEM_E_INVALID_PARAMETER);
|
|
}
|
|
|
|
if (IsVerboseLoggingEnabled())
|
|
{
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LogMessage2(L"GetInstancesByQueryAsynch (%s) - Succeeded", query);
|
|
}
|
|
else
|
|
{
|
|
LogMessage3(L"GetInstancesByQueryAsynch (%s) - FAILED (%x)", query, hr);
|
|
}
|
|
}
|
|
|
|
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::ProviderTimer);
|
|
|
|
return hr;
|
|
}
|
|
|
|
IWbemServices *CWbemProviderGlue::InternalGetNamespaceConnection(
|
|
|
|
LPCWSTR pwszNameSpace
|
|
)
|
|
{
|
|
IWbemServices *pWbemServices = NULL;
|
|
|
|
bstr_t bstrNamespace;
|
|
|
|
// Root\CimV2 is the default name space
|
|
if ( NULL != pwszNameSpace && L'\0' != *pwszNameSpace )
|
|
{
|
|
bstrNamespace = pwszNameSpace;
|
|
}
|
|
else
|
|
{
|
|
ASSERT_BREAK(DEPRECATED);
|
|
bstrNamespace = DEFAULT_NAMESPACE;
|
|
}
|
|
|
|
if (IsVerboseLoggingEnabled())
|
|
{
|
|
LogMessage3(L"%s%s", IDS_GETNAMESPACECONNECTION, (LPCWSTR)bstrNamespace);
|
|
}
|
|
|
|
_wcsupr(bstrNamespace);
|
|
|
|
// If we are looking for the namespace our class is in, we already
|
|
// got an IWbemServices pointer for this from Initialize
|
|
if (m_strNamespace.Compare(bstrNamespace) == 0)
|
|
{
|
|
pWbemServices = m_pServices;
|
|
pWbemServices->AddRef();
|
|
}
|
|
else
|
|
{
|
|
IWbemLocatorPtr pIWbemLocator;
|
|
|
|
HRESULT hRes = CoCreateInstance (
|
|
|
|
CLSID_WbemLocator, //CLSID_WbemAdministrativeLocator,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
|
|
IID_IUnknown,
|
|
( void ** ) &pIWbemLocator
|
|
) ;
|
|
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
hRes = pIWbemLocator->ConnectServer(bstrNamespace, // Namespace
|
|
NULL, // Userid
|
|
NULL, // PW
|
|
NULL, // Locale
|
|
0, // flags
|
|
NULL, // Authority
|
|
NULL, // Context
|
|
&pWbemServices
|
|
);
|
|
|
|
if (FAILED(hRes))
|
|
{
|
|
LogErrorMessage3(L"Failed to Connectserver to namespace %s (%x)",
|
|
(LPCWSTR)bstrNamespace, hRes);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LogErrorMessage2(L"Failed to get locator (%x)", hRes);
|
|
}
|
|
}
|
|
|
|
return pWbemServices;
|
|
}
|
|
|
|
IWbemServices *WINAPI CWbemProviderGlue::GetNamespaceConnection( LPCWSTR wszNameSpace, MethodContext *pMethodContext )
|
|
{
|
|
IWbemServices *pServices = NULL;
|
|
CWbemProviderGlue *pGlue = NULL;
|
|
|
|
if ( pMethodContext && (pGlue = pMethodContext->GetProviderGlue()) )
|
|
{
|
|
pServices = pGlue->InternalGetNamespaceConnection(wszNameSpace);
|
|
}
|
|
else
|
|
{
|
|
pServices = GetNamespaceConnection(wszNameSpace);
|
|
}
|
|
|
|
return pServices;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::FrameworkLoginDLL
|
|
//
|
|
// Static entry point for providers to register their DLL with
|
|
// the framework. This PLONG must be the same one used in
|
|
// FrameworkLogoffDll and as the parameter to the CWbemGlueFactory
|
|
// constructor.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL CWbemProviderGlue::FrameworkLoginDLL(LPCWSTR pszName, PLONG plRefCount)
|
|
{
|
|
BOOL bRet = TRUE;
|
|
LogMessage3(L"%s%s", IDS_DLLLOGGED, pszName);
|
|
|
|
// If this *is* null, that means we are using the backword compatibility
|
|
// version of FrameworkLoginDLL, which uses CWbemProviderGlue::s_lObjects
|
|
// which has already been initialized.
|
|
if (plRefCount != NULL)
|
|
{
|
|
*plRefCount = 0;
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::FrameworkLogoffDLL
|
|
//
|
|
// Static entry point for providers to determine whether they
|
|
// should return TRUE to DllCanUnloadNow. This PLONG must be the
|
|
// same one used in FrameworkLoginDLL and as the parameter to the
|
|
// CWbemGlueFactory constructor.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL CWbemProviderGlue::FrameworkLogoffDLL(LPCWSTR pszName, PLONG plRefCount)
|
|
{
|
|
BOOL bRet = TRUE;
|
|
|
|
LogMessage3(L"%s%s", IDS_DLLUNLOGGED, pszName);
|
|
|
|
// If this *is* null, that means we are using the backword compatibility
|
|
// version of FrameworkLoginDLL
|
|
if (plRefCount != NULL)
|
|
{
|
|
bRet = *plRefCount == 0;
|
|
}
|
|
else
|
|
{
|
|
bRet = CWbemProviderGlue::s_lObjects == 0;
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::AddToFactoryMap
|
|
//
|
|
// Adds a new CWbemGlueFactory to the s_factorymap map.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
VOID CWbemProviderGlue::AddToFactoryMap(const CWbemGlueFactory *pGlue, PLONG plRefCount)
|
|
{
|
|
LockFactoryMap();
|
|
OnDelete0 < void (__stdcall *)(void), CWbemProviderGlue::UnlockFactoryMap> SmartUnlockFactoryMap ;
|
|
|
|
// If this *is* null, that means we are using the backword compatibility
|
|
// version of FrameworkLoginDLL
|
|
if (plRefCount != NULL)
|
|
{
|
|
CWbemProviderGlue::s_factorymap[pGlue] = plRefCount;
|
|
}
|
|
else
|
|
{
|
|
CWbemProviderGlue::s_factorymap[pGlue] = &CWbemProviderGlue::s_lObjects;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::RemoveFromFactoryMap
|
|
//
|
|
// Removes a CWbemGlueFactory from the s_factorymap map.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
VOID CWbemProviderGlue::RemoveFromFactoryMap(const CWbemGlueFactory *pGlue)
|
|
{
|
|
EnterCriticalSectionWait ecs ( &s_csFactoryMap );
|
|
LeaveCriticalSectionScope lcs ( &s_csFactoryMap );
|
|
|
|
try
|
|
{
|
|
bool bFound = false;
|
|
PTR2PLONG::iterator mapIter;
|
|
|
|
mapIter = s_factorymap.find(pGlue);
|
|
|
|
if ( mapIter != s_factorymap.end() )
|
|
{
|
|
s_factorymap.erase(mapIter);
|
|
}
|
|
else
|
|
{
|
|
LogErrorMessage2(L"Can't find factory in map: %p", pGlue);
|
|
}
|
|
}
|
|
catch( ... )
|
|
{
|
|
// we should not be here
|
|
// do not re-throw (called from destructor)
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::IncrementMapCount
|
|
//
|
|
// Increments the refcount on a DLL
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
LONG CWbemProviderGlue::IncrementMapCount(const CWbemGlueFactory *pGlue)
|
|
{
|
|
LONG lRet = -1;
|
|
LockFactoryMap();
|
|
OnDelete0 < void (__stdcall *)(void), CWbemProviderGlue::UnlockFactoryMap> SmartUnlockFactoryMap ;
|
|
|
|
PTR2PLONG::iterator mapIter;
|
|
mapIter = CWbemProviderGlue::s_factorymap.find( pGlue );
|
|
|
|
if (mapIter != CWbemProviderGlue::s_factorymap.end())
|
|
{
|
|
lRet = InterlockedIncrement((*mapIter).second);
|
|
}
|
|
else
|
|
{
|
|
// This is very bad. This should have been created
|
|
// at CWbemGlueFactory constructor time.
|
|
LogErrorMessage2(L"Can't find factory in map: %p", pGlue);
|
|
}
|
|
|
|
return lRet;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::IncrementMapCount
|
|
//
|
|
// Increments the refcount on a DLL
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
LONG CWbemProviderGlue::IncrementMapCount(PLONG pCount)
|
|
{
|
|
return InterlockedIncrement(pCount);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::DecrementMapCount
|
|
//
|
|
// Decrements the refcount on a DLL
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
LONG CWbemProviderGlue::DecrementMapCount(const CWbemGlueFactory *pGlue)
|
|
{
|
|
LONG lRet = -1;
|
|
|
|
EnterCriticalSectionWait ecs ( &s_csFactoryMap );
|
|
LeaveCriticalSectionScope lcs ( &s_csFactoryMap );
|
|
|
|
try
|
|
{
|
|
// Find the matching CWbemGlueFactory in the CWbemGlueFactory<->refcount map
|
|
PTR2PLONG::iterator mapIter;
|
|
mapIter = CWbemProviderGlue::s_factorymap.find( pGlue );
|
|
|
|
if (mapIter != CWbemProviderGlue::s_factorymap.end())
|
|
{
|
|
lRet = InterlockedDecrement((*mapIter).second);
|
|
|
|
if (lRet < 0)
|
|
{
|
|
LogErrorMessage2(L"RefCount < 0 for glue %p", pGlue);
|
|
ASSERT_BREAK(DUPLICATE_RELEASE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LogErrorMessage2(L"Can't find factory in map: %p", pGlue);
|
|
}
|
|
}
|
|
catch ( ... )
|
|
{
|
|
// we should not be here
|
|
// do not re-throw (called from destructor)
|
|
}
|
|
|
|
return lRet;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::DecrementMapCount
|
|
//
|
|
// Decrements the refcount on a DLL
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
LONG CWbemProviderGlue::DecrementMapCount(PLONG pCount)
|
|
{
|
|
LONG lRet = InterlockedDecrement(pCount);
|
|
|
|
try
|
|
{
|
|
if (lRet < 0)
|
|
{
|
|
LogErrorMessage2(L"RefCount < 0 for %p", pCount);
|
|
ASSERT_BREAK(DUPLICATE_RELEASE);
|
|
}
|
|
}
|
|
catch ( ... )
|
|
{
|
|
// we should not be here
|
|
// do not re-throw (called from destructor)
|
|
}
|
|
|
|
return lRet;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::GetMapCountPtr
|
|
//
|
|
// Returns the pointer to the plong for this glue factory
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
PLONG CWbemProviderGlue::GetMapCountPtr(const CWbemGlueFactory *pGlue)
|
|
{
|
|
PLONG pRet = NULL;
|
|
LockFactoryMap();
|
|
OnDelete0 < void (__stdcall *)(void), CWbemProviderGlue::UnlockFactoryMap> SmartUnlockFactoryMap ;
|
|
|
|
// Find the matching CWbemGlueFactory in the CWbemGlueFactory<->refcount map
|
|
PTR2PLONG::iterator mapIter;
|
|
mapIter = CWbemProviderGlue::s_factorymap.find( pGlue );
|
|
|
|
if (mapIter != CWbemProviderGlue::s_factorymap.end())
|
|
{
|
|
pRet = mapIter->second;
|
|
}
|
|
else
|
|
{
|
|
LogErrorMessage2(L"Can't find factory in map: %p", pGlue);
|
|
}
|
|
|
|
return pRet;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CWbemProviderGlue::AddFlushPtr
|
|
//
|
|
// Add the this pointer to a provider to the list of providers
|
|
// that need to be flushed.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
void CWbemProviderGlue::AddFlushPtr(LPVOID pVoid)
|
|
{
|
|
CLockWrapper lockwrap(m_csFlushPtrs);
|
|
|
|
m_FlushPtrs.insert(pVoid);
|
|
}
|