//*************************************************************************** // // Copyright © Microsoft Corporation. All rights reserved. // // WBEMGLUE.CPP // // Purpose: Implementation of CWbemProviderGlue class // //*************************************************************************** #include "precomp.h" #include #include #include #include #include #include #include #include #include #include #define SECURITY_WIN32 #include #include #include "FWStrings.h" #include "MultiPlat.h" #include #include #include #include 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 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 smartpKeyNames(pKeyNames); SafeArrayGetUBound(pKeyNames, 1, &nBiggestName); for (i = 0; i <= nBiggestName; i++) { if (SUCCEEDED(SafeArrayGetElement( pKeyNames, &i, &t_bstrName ))) { OnDeleteIf 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 *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 *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 *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 *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 *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 *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 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); }