#include #include #include #include #include #include #include #include #include #include #include "PolicSOM.h" #ifdef TIME_TRIALS #include #pragma message("!! Including time trial code !!") StopWatch EvaluateTimer(L"Somfilter Evaluation", L"C:\\Som.Evaluate.log"); #endif /******************************\ **** POLICY PROVIDER HELPERS *** \******************************/ #define SOM_RDN L"CN=SOM,CN=WMIPolicy,CN=System" // returns addref'd pointer back to WinMgmt IWbemServices* CPolicySOM::GetWMIServices() { // CInCritSec lock(&m_CS); if (m_pWMIMgmt != NULL) ((IWbemServices*)m_pWMIMgmt)->AddRef(); return m_pWMIMgmt; } UINT NextPattern(wchar_t *a_pString, UINT a_uOffset, wchar_t *a_pPattern) { wchar_t *start; start = wcsstr(a_pString + a_uOffset, a_pPattern); return (start < a_pString ? 0 : (UINT)(start - a_pString)); } // returns addref'd pointer back to m_pADMgmt IADsContainer *CPolicySOM::GetADServices(CComBSTR &a_bstrIPDomainName, HRESULT &a_hres) { a_hres = WBEM_S_NO_ERROR; CComQIPtr pADsContainer; CComBSTR bstrADDomainName, ObjPath; UINT uOffsetS = 0, uOffsetE = 0; // **** if this is the 1st time through, get name of domain controller { CInCritSec lock(&m_CS); if(VT_BSTR != m_vDsLocalContext.vt) { CComPtr pRootDSE; CComVariant vDomain; // **** get pointer to AD policy template table a_hres = ADsOpenObject(L"LDAP://rootDSE", NULL, NULL, ADS_SECURE_AUTHENTICATION | ADS_USE_SEALING | ADS_USE_SIGNING, IID_IADs, (void**)&pRootDSE); if(FAILED(a_hres)) { ERRORTRACE((LOG_ESS, "POLICMAN: (ADsGetObject) could not get object: LDAP://rootDSE, 0x%08X\n", a_hres)); return NULL; } else { a_hres = pRootDSE->Get(g_bstrMISCdefaultNamingContext,&m_vDsLocalContext); if(FAILED(a_hres)) { ERRORTRACE((LOG_ESS, "POLICMAN: (IADs::Get) could not get defaultNamingContext, 0x%08X\n", a_hres)); return NULL; } } } } // **** translate bstrADServerName to bstrIPServerName if(!a_bstrIPDomainName) { bstrADDomainName = m_vDsLocalContext.bstrVal; uOffsetS = 3; while((uOffsetS < bstrADDomainName.Length()) && (uOffsetE = NextPattern(m_vDsLocalContext.bstrVal, uOffsetS, L",DC="))) { if(uOffsetS && (uOffsetS == uOffsetE)) return NULL; a_bstrIPDomainName.Append(m_vDsLocalContext.bstrVal + uOffsetS, uOffsetE - uOffsetS); uOffsetS = uOffsetE + 4; if(uOffsetS < bstrADDomainName.Length()) a_bstrIPDomainName.Append(L"."); } if(uOffsetS < bstrADDomainName.Length()) a_bstrIPDomainName.Append(m_vDsLocalContext.bstrVal + uOffsetS); } // **** translate bstrIPServerName to bstrADServerName else { bstrADDomainName.Append(L"DC="); while((uOffsetS < a_bstrIPDomainName.Length()) && (uOffsetE = NextPattern(a_bstrIPDomainName, uOffsetS, L"."))) { if(uOffsetS && (uOffsetS == uOffsetE)) return NULL; bstrADDomainName.Append(a_bstrIPDomainName + uOffsetS, uOffsetE - uOffsetS); uOffsetS = uOffsetE + 1; if(uOffsetS < a_bstrIPDomainName.Length()) bstrADDomainName.Append(L",DC="); } if(uOffsetS < a_bstrIPDomainName.Length()) bstrADDomainName.Append(a_bstrIPDomainName + uOffsetS); } ObjPath.Append(L"LDAP://"); ObjPath.Append(a_bstrIPDomainName); ObjPath.Append(L"/"); ObjPath.Append(SOM_RDN); ObjPath.Append(L","); ObjPath.Append(bstrADDomainName); if(SUCCEEDED(a_hres)) { a_hres = ADsOpenObject(ObjPath, NULL, NULL, ADS_SECURE_AUTHENTICATION | ADS_USE_SEALING | ADS_USE_SIGNING, IID_IADsContainer, (void**) &pADsContainer); if(FAILED(a_hres)) a_hres = WBEM_E_INITIALIZATION_FAILURE; } return pADsContainer.Detach(); } // returns false if services pointer has already been set bool CPolicySOM::SetWMIServices(IWbemServices* pServices) { CInCritSec lock(&m_CS); bool bOldOneNull = FALSE; if (bOldOneNull = (m_pWMIMgmt == NULL)) { m_pWMIMgmt = pServices; if(pServices) pServices->AddRef(); } return bOldOneNull; } // returns false if services pointer has already been set bool CPolicySOM::SetADServices(IADsContainer* pServices, unsigned context) { CInCritSec lock(&m_CS); bool bOldOneNull = TRUE; switch(context) { case AD_LOCAL_CONTEXT : case AD_GLOBAL_CONTEXT : m_pADMgmt[context] = pServices; bOldOneNull = (m_pADMgmt[context] == NULL); break; default : ; } return bOldOneNull; } CPolicySOM::~CPolicySOM() { // WMI services object m_pWMIMgmt= NULL; // AD services object for(int i = 0; i < AD_MAX_CONTEXT; i++) m_pADMgmt[i] = NULL; }; void* CPolicySOM::GetInterface(REFIID riid) { if(riid == IID_IWbemServices) return &m_XProvider; else if(riid == IID_IWbemProviderInit) return &m_XInit; else return NULL; } /*********************************\ *** Som Specific Implementation *** \*********************************/ // returns addref'd pointer to class object IWbemClassObject* CPolicySOM::XProvider::GetSomClass() { if (m_pSOMClassObject == NULL) { CInCritSec lock(&m_pObject->m_CS); if (m_pSOMClassObject == NULL) { CComPtr pWinMgmt = m_pObject->GetWMIServices(); if (pWinMgmt != NULL) { pWinMgmt->GetObject(g_bstrClassSom, WBEM_FLAG_RETURN_WBEM_COMPLETE, NULL, &m_pSOMClassObject, NULL); } } } return m_pSOMClassObject; } // returns addref'd pointer to emply class instance IWbemClassObject* CPolicySOM::XProvider::GetSomInstance() { CComQIPtr pObj; CComQIPtr pClass; if (pClass = GetSomClass()) { pClass->SpawnInstance(0, &pObj); } return pObj.Detach(); } HRESULT CPolicySOM::XProvider::GetLocator(IWbemLocator*& pLocator) { HRESULT hr = WBEM_S_NO_ERROR; { CInCritSec lock(&m_pObject->m_CS); if (!m_pLocator) hr = CoCreateInstance(CLSID_WbemAdministrativeLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (void**)&m_pLocator); } if(SUCCEEDED(hr) && !(!m_pLocator)) pLocator = m_pLocator; return hr; } // get namespace denoted by namespaceName // will release pNamespace if non-null on way in HRESULT CPolicySOM::XProvider::GetNewNamespace(BSTR namespaceName, IWbemServices*& pNamespace) { HRESULT hr = WBEM_E_FAILED; if (pNamespace) { pNamespace->Release(); pNamespace = NULL; } IWbemLocator* pLocator = NULL; if (SUCCEEDED(hr = GetLocator(pLocator))) { hr = pLocator->ConnectServer(namespaceName, NULL, NULL, NULL, 0, NULL, NULL, &pNamespace); } return hr; } // evaulate a single rule // pNamespace & namespaceName may be NULL on entry // may be different upon exit // this is a rudimentary caching mechanism, // assuming that most of the namespaces in the rules will be the same. HRESULT CPolicySOM::XProvider::EvaluateRule(IWbemServices*& pNamespace, BSTR& namespaceName, IWbemClassObject* pRule, bool& bResult) { VARIANT v; VariantInit(&v); // assume failure HRESULT hr = WBEM_E_FAILED; bResult = false; // check to see if we're still on the same namespace if (FAILED(hr = pRule->Get(L"TargetNamespace", 0, &v, NULL, NULL))) bResult = false; else { if ((pNamespace == NULL) || (_wcsicmp(namespaceName, v.bstrVal) != 0)) if (SUCCEEDED(hr = GetNewNamespace(v.bstrVal, pNamespace))) { // keep copy of name if (namespaceName) { if (!SysReAllocString(&namespaceName, v.bstrVal)) hr = WBEM_E_OUT_OF_MEMORY; } else if (NULL == (namespaceName = SysAllocString(v.bstrVal))) hr = WBEM_E_OUT_OF_MEMORY; } VariantClear(&v); } // if we're still on track... if (SUCCEEDED(hr) && SUCCEEDED(hr = pRule->Get(g_bstrMISCQuery, 0, &v, NULL, NULL))) { #ifdef TIME_TRIALS EvaluateTimer.Start(StopWatch::AtomicTimer); #endif IEnumWbemClassObject *pEnumerator = NULL; if (SUCCEEDED(hr = pNamespace->ExecQuery(g_bstrMISCWQL, v.bstrVal, WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator))) { #ifdef TIME_TRIALS EvaluateTimer.Start(StopWatch::ProviderTimer); #endif ULONG uReturned = 0; IWbemClassObject* pWhoCares = NULL; if (SUCCEEDED(hr = pEnumerator->Next(30000, 1, &pWhoCares, &uReturned)) && uReturned > 0) { // we don't care at all about the result set // just whether there is anything *in* the result set bResult = true; pWhoCares->Release(); } if(hr == WBEM_S_TIMEDOUT) hr = WBEM_E_TIMED_OUT; pEnumerator->Release(); } #ifdef TIME_TRIALS else EvaluateTimer.Start(StopWatch::ProviderTimer); #endif VariantClear(&v); } // s_false returned when no objects are returned from 'next' // THIS function has successfully determined that the query failed. if (hr == (HRESULT)WBEM_S_FALSE) hr = WBEM_S_NO_ERROR; return hr; } // loop through all rules // grab namespace & try each query // TODO: Optimize by caching namespace pointers. HRESULT CPolicySOM::XProvider::Evaluate(IWbemClassObject* pObj, IWbemClassObject* pOutInstance) { HRESULT hr = WBEM_S_NO_ERROR; HRESULT hrEval = WBEM_S_NO_ERROR; // innocent until proven guilty bool bResult = true; VARIANT v; VariantInit(&v); if (SUCCEEDED(hr = pObj->Get(L"Rules", 0, &v, NULL, NULL))) { SafeArray rules(&v); long nRules = rules.Size(); // first run optimization: we'll hold onto each namespace as it comes in // in hopes that the NEXT one will be in the same namespace // in practice - it probably will be IWbemServices* pNamespace = NULL; BSTR namespaceName = NULL; // with each rule: // get namespace name // if different than the one we're currently playing with // get namespace // issue query // count results for(UINT i = 0; (i < nRules) && bResult && SUCCEEDED(hrEval); i++) { if (rules[i]) { IWbemClassObject* pRule = NULL; if (SUCCEEDED(rules[i]->QueryInterface(IID_IWbemClassObject, (void**)&pRule))) { hrEval = EvaluateRule(pNamespace, namespaceName, pRule, bResult); pRule->Release(); pRule = NULL; } else { bResult = FALSE; hrEval = hr = WBEM_E_INVALID_PARAMETER; } } } // clean up after yourself VariantClear(&v); if (pNamespace) pNamespace->Release(); if (namespaceName) SysFreeString(namespaceName); } // we done - tell somebody about it! if (SUCCEEDED(hr)) { HRESULT hrDebug; VARIANT v1; VariantInit(&v1); v1.vt = VT_I4; if (SUCCEEDED(hrEval)) v1.lVal = bResult ? S_OK : S_FALSE; else v1.lVal = hrEval; hrDebug = pOutInstance->Put(L"ReturnValue", 0, &v1, NULL); } return hr; } // loop through each of the references in input obj // call evaluate for each, // TODO: Optimize w/ ExecMethodASYNC HRESULT CPolicySOM::XProvider::BatchEvaluate(IWbemClassObject* pObj, IWbemClassObject* pOutInstance, IWbemServices* pPolicyNamespace) { HRESULT hr = WBEM_S_NO_ERROR; if (pObj == NULL) return WBEM_E_INVALID_PARAMETER; VARIANT vFilters; VariantInit(&vFilters); BSTR methodName = SysAllocString(L"Evaluate"); CSysFreeMe freeEvil(methodName); SAFEARRAY* pResults = NULL; if (SUCCEEDED(hr = pObj->Get(L"filters", 0, &vFilters, NULL, NULL))) { if ((vFilters.parray == NULL) || (vFilters.parray->cDims != 1) || (vFilters.parray->rgsabound[0].cElements == 0)) hr = WBEM_E_INVALID_PARAMETER; else { long index, lUbound = 0; SafeArrayGetUBound(vFilters.parray, 1, &lUbound); SAFEARRAYBOUND bounds = {lUbound +1, 0}; pResults = SafeArrayCreate(VT_I4, 1, &bounds); if (!pResults) return WBEM_E_OUT_OF_MEMORY; for (index = 0; (index <= lUbound) && SUCCEEDED(hr); index++) { BSTR path = NULL; if (SUCCEEDED(hr = SafeArrayGetElement(vFilters.parray, &index, &path))) { IWbemClassObject* pGazotta = NULL; if (SUCCEEDED(hr = pPolicyNamespace->ExecMethod(path, methodName, 0, NULL, NULL, &pGazotta, NULL))) { CReleaseMe relGazotta(pGazotta); VARIANT v; VariantInit(&v); hr = pGazotta->Get(L"ReturnValue", 0, &v, NULL, NULL); hr = SafeArrayPutElement(pResults, &index, &v.lVal); } } SysFreeString(path); } } } if (SUCCEEDED(hr)) { VARIANT v; VariantInit(&v); v.vt = VT_I4 | VT_ARRAY; v.parray = pResults; hr = pOutInstance->Put(L"Results", 0, &v, NULL); // no clear - array is deleted separately. VariantInit(&v); v.vt = VT_I4; v.lVal = hr; hr = pOutInstance->Put(L"ReturnValue", 0, &v, NULL); } if (pResults) SafeArrayDestroy(pResults); VariantClear(&vFilters); return hr; } /*************************\ *** IWbemProviderInit *** \*************************/ STDMETHODIMP CPolicySOM::XInit::Initialize( LPWSTR, LONG, LPWSTR, LPWSTR, IWbemServices* pServices, IWbemContext* pCtxt, IWbemProviderInitSink* pSink) { HRESULT hres = WBEM_S_NO_ERROR, hres2 = WBEM_S_NO_ERROR; // **** impersonate client for security hres = CoImpersonateClient(); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "POLICMAN: (CoImpersonateClient) could not assume client permissions, 0x%08X\n", hres)); return WBEM_S_ACCESS_DENIED; } else { // **** save WMI name space pointer m_pObject->SetWMIServices(pServices); } hres2 = pSink->SetStatus(hres, 0); if(FAILED(hres2)) { ERRORTRACE((LOG_ESS, "POLICMAN: could not set return status\n")); if(SUCCEEDED(hres)) hres = hres2; } // **** create LDAP name manipulation utility object { CInCritSec lock(&(m_pObject->m_CS)); if(m_pObject->m_pADPathObj != NULL) hres = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER, IID_IADsPathname, (void**)&(m_pObject->m_pADPathObj)); } CoRevertToSelf(); return hres; } /*******************\ *** IWbemServices *** \*******************/ STDMETHODIMP CPolicySOM::XProvider::GetObjectAsync( /* [in] */ const BSTR ObjectPath, /* [in] */ long lFlags, /* [in] */ IWbemContext __RPC_FAR *pCtx, /* [in] */ IWbemObjectSink __RPC_FAR *pResponseHandler) { HRESULT hres = WBEM_S_NO_ERROR, hres2 = WBEM_S_NO_ERROR; CComPtr pNamespace; CComPtr pADsContainer; CComPtr pDisp; CComPtr pObj; CComPtr pDirObj; VARIANT *pvkeyID = NULL, *pvDomain = NULL; // **** impersonate client for security hres = CoImpersonateClient(); if (FAILED(hres)) { ERRORTRACE((LOG_ESS, "POLICMAN: (CoImpersonateClient) could not assume callers permissions, 0x%08X\n",hres)); hres = WBEM_E_ACCESS_DENIED; } else { // **** Check arguments if(ObjectPath == NULL || pResponseHandler == NULL) { ERRORTRACE((LOG_ESS, "POLICMAN: object path and/or return object are NULL\n")); hres = WBEM_E_INVALID_PARAMETER; } else { // **** parse object path CObjectPathParser ObjPath(e_ParserAcceptRelativeNamespace); ParsedObjectPath *pParsedObjectPath = NULL; if((ObjPath.NoError != ObjPath.Parse(ObjectPath, &pParsedObjectPath)) || (0 != _wcsicmp(g_bstrClassSom, pParsedObjectPath->m_pClass)) || (2 != pParsedObjectPath->m_dwNumKeys)) { ERRORTRACE((LOG_ESS, "POLICMAN: Parse error for object: %S\n", ObjectPath)); hres = WBEM_E_INVALID_QUERY; } else { for(int x = 0; x < pParsedObjectPath->m_dwNumKeys; x++) { if(0 == _wcsicmp((*(pParsedObjectPath->m_paKeys + x))->m_pName, g_bstrDomain)) pvDomain = &((*(pParsedObjectPath->m_paKeys + x))->m_vValue); else if(0 == _wcsicmp((*(pParsedObjectPath->m_paKeys + x))->m_pName, g_bstrID)) pvkeyID = &((*(pParsedObjectPath->m_paKeys + x))->m_vValue); } pNamespace.Attach(m_pObject->GetWMIServices()); CComBSTR bstrDomain = ((pvDomain && pvDomain->vt == VT_BSTR) ? pvDomain->bstrVal : NULL); pADsContainer.Attach(m_pObject->GetADServices(bstrDomain, hres)); if((FAILED(hres)) || (pNamespace == NULL) || (pADsContainer == NULL)) { ERRORTRACE((LOG_ESS, "POLICMAN: WMI and/or AD services not initialized\n")); hres = ADSIToWMIErrorCodes(hres); } else { try { // **** Get pointer to instance in AD CComBSTR bstrKeyID(L"CN="); bstrKeyID.Append(V_BSTR(pvkeyID)); hres = pADsContainer->GetObject(g_bstrADClassSom, bstrKeyID, &pDisp); if(FAILED(hres)) hres = ADSIToWMIErrorCodes(hres); else { hres = pDisp->QueryInterface(IID_IDirectoryObject, (void **)&pDirObj); if(SUCCEEDED(hres)) { // **** Get the instance and send it back hres = Som_ADToCIM(&pObj, pDirObj, pNamespace); if(FAILED(hres)) hres = ADSIToWMIErrorCodes(hres); if(pObj == NULL) hres = WBEM_E_FAILED; // **** set domain name for object if(SUCCEEDED(hres)) { VARIANT v1; v1.bstrVal = (BSTR)bstrDomain; v1.vt = VT_BSTR; hres = pObj->Put(g_bstrDomain, 0, &v1, 0); // **** Set object pResponseHandler->Indicate(1, &pObj); } } } } catch(long hret) { hres = ADSIToWMIErrorCodes(hret); ERRORTRACE((LOG_ESS, "POLICMAN: Translation of Policy object from AD to WMI generated HRESULT 0x%08X\n", hres)); } catch(wchar_t *swErrString) { ERRORTRACE((LOG_ESS, "POLICMAN: Caught Exception: %S\n", swErrString)); hres = WBEM_E_FAILED; } catch(...) { ERRORTRACE((LOG_ESS, "POLICMAN: Caught UNKNOWN Exception\n")); hres = WBEM_E_FAILED; } } } ObjPath.Free(pParsedObjectPath); hres2 = pResponseHandler->SetStatus(0,hres, NULL, NULL); if(FAILED(hres2)) { ERRORTRACE((LOG_ESS, "POLICMAN: could not set return status\n")); if(SUCCEEDED(hres)) hres = hres2; } } CoRevertToSelf(); } return hres; } STDMETHODIMP CPolicySOM::XProvider::CreateInstanceEnumAsync( /* [in] */ const BSTR Class, /* [in] */ long lFlags, /* [in] */ IWbemContext __RPC_FAR *pCtx, /* [in] */ IWbemObjectSink __RPC_FAR *pResponseHandler) { return WBEM_E_NOT_SUPPORTED; } // validate that the rules contained in pInst are proper syntax // if they are not, an error object is created & an error returned HRESULT CPolicySOM::XProvider::ValidateRules(IWbemClassObject* pInst, IWbemClassObject*& pErrorObject) { // init the toys we'll be playing with HRESULT hr = WBEM_S_NO_ERROR; bool bBadQuery = false; VARIANT vRules; VariantInit(&vRules); SAFEARRAY* pResults = NULL; if (FAILED(pInst->Get(L"Rules", 0, &vRules, NULL, NULL)) || (vRules.vt != (VT_UNKNOWN | VT_ARRAY))) hr = WBEM_E_INVALID_PARAMETER; else { // good to go, we'll create the array to keep logic simple long index, lUbound = 0; SafeArrayGetUBound(vRules.parray, 1, &lUbound); SAFEARRAYBOUND bounds = {lUbound +1, 0}; pResults = SafeArrayCreate(VT_I4, 1, &bounds); if (!pResults) hr = WBEM_E_OUT_OF_MEMORY; else for (index = 0; (index <= lUbound) && SUCCEEDED(hr); index++) { // get the MSFT_Rule out of the MSFT_SomFilter IWbemClassObject* pRule = NULL; if (SUCCEEDED(hr = SafeArrayGetElement(vRules.parray, &index, &pRule))) { HRESULT hrParse = 0; VARIANT vQueryLanguage; VariantInit(&vQueryLanguage); if (SUCCEEDED(hr = pRule->Get(L"QueryLanguage", 0, &vQueryLanguage, NULL, NULL)) && (vQueryLanguage.vt == VT_BSTR) && (vQueryLanguage.bstrVal != NULL)) { if (0 != _wcsicmp(vQueryLanguage.bstrVal, L"WQL")) { hrParse = WBEM_E_INVALID_QUERY_TYPE; bBadQuery = true; } else { VARIANT vQuery; VariantInit(&vQuery); // get the query out of the MSFT_Rule. if (SUCCEEDED(hr = pRule->Get(L"Query", 0, &vQuery, NULL, NULL)) && (vQuery.vt == VT_BSTR) && (vQuery.bstrVal != NULL)) { CTextLexSource src(vQuery.bstrVal); QL1_Parser parser(&src); QL_LEVEL_1_RPN_EXPRESSION *pExp = NULL; // if it parses, we good, else we bad. if(parser.Parse(&pExp)) { hrParse = WBEM_E_INVALID_QUERY; bBadQuery = true; } if (pExp) delete pExp; } else hrParse = WBEM_E_INVALID_PARAMETER; VariantClear(&vQuery); } } else hrParse = WBEM_E_INVALID_PARAMETER; hr = SafeArrayPutElement(pResults, &index, (void*)&hrParse); pRule->Release(); VariantClear(&vQueryLanguage); } } } // if we found a bad query, we create an error object to hold the info if (bBadQuery) { IWbemServices* pSvc = m_pObject->GetWMIServices(); IWbemClassObject* pErrorClass = NULL; BSTR name = SysAllocString(L"SomFilterPutStatus"); if (pSvc && name && SUCCEEDED(hr = pSvc->GetObject(name, 0, NULL, &pErrorClass, NULL)) && SUCCEEDED(hr = pErrorClass->SpawnInstance(0, &pErrorObject))) { hr = WBEM_E_INVALID_PARAMETER; HRESULT hrDebug; // variant to hold array - don't clear it, the array is destroyed elsewhere VARIANT vResultArray; VariantInit(&vResultArray); vResultArray.vt = VT_I4 | VT_ARRAY; vResultArray.parray = pResults; hrDebug = pErrorObject->Put(L"RuleValidationResults", 0, &vResultArray, NULL); // other interesting error vals. VARIANT vTemp; vTemp.vt = VT_BSTR; vTemp.bstrVal = SysAllocString(L"PutInstance"); hrDebug = pErrorObject->Put(L"Operation",0,&vTemp,NULL); SysFreeString(vTemp.bstrVal); vTemp.bstrVal = SysAllocString(L"PolicSOM"); hrDebug = pErrorObject->Put(L"ProviderName",0,&vTemp,NULL); SysFreeString(vTemp.bstrVal); vTemp.vt = VT_I4; vTemp.lVal = WBEM_E_INVALID_QUERY; hrDebug = pErrorObject->Put(L"StatusCode",0,&vTemp,NULL); //BSTR debuggy = NULL; //pErrorObject->GetObjectText(0, &debuggy); } if (pSvc) pSvc->Release(); if (name) SysFreeString(name); if (pErrorClass) pErrorClass->Release(); } // cleanup VariantClear(&vRules); if (pResults) SafeArrayDestroy(pResults); return hr; } STDMETHODIMP CPolicySOM::XProvider::PutInstanceAsync( /* [in] */ IWbemClassObject __RPC_FAR *pInst, /* [in] */ long lFlags, /* [in] */ IWbemContext __RPC_FAR *pCtx, /* [in] */ IWbemObjectSink __RPC_FAR *pResponseHandler) { HRESULT hres = WBEM_S_NO_ERROR, hres2 = WBEM_S_NO_ERROR; CComPtr pADsContainer; CComPtr pDirObj; CComVariant v1, vRelPath; ADsStruct pInfo; // **** impersonate client hres = CoImpersonateClient(); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "POLICMAN: (CoImpersonateClient) could not assume callers permissions, 0x%08X\n",hres)); hres = WBEM_E_ACCESS_DENIED; } else { // **** check arguments if((NULL == pInst) || (NULL == pResponseHandler)) { ERRORTRACE((LOG_ESS, "POLICMAN: (CoImpersonateClient) could not assume callers permissions, 0x%08X\n",hres)); hres = WBEM_E_ACCESS_DENIED; } else { IWbemClassObject* pErrorObject = NULL; if SUCCEEDED(hres = ValidateRules(pInst, pErrorObject)) { // **** put policy obj into AD try { EnsureID(pInst, NULL); // **** aquire AD path in which to place object hres = pInst->Get(g_bstrDomain, 0, &v1, NULL, NULL); if(FAILED(hres)) return hres; CComBSTR bstrDomain = (v1.vt == VT_BSTR ? v1.bstrVal : NULL); pADsContainer.Attach(m_pObject->GetADServices(bstrDomain, hres)); if((FAILED(hres)) || (pADsContainer == NULL)) { ERRORTRACE((LOG_ESS, "POLICMAN: Could not find or connect to domain: %S, 0x%08X\n", V_BSTR(&v1), hres)); return ADSIToWMIErrorCodes(hres); } else { VARIANT _v; VariantInit(&_v); _v.bstrVal = (BSTR)bstrDomain; _v.vt = VT_BSTR; hres = pInst->Put(g_bstrDomain, 0, &_v, 0); } hres = pADsContainer->QueryInterface(IID_IDirectoryObject, (void **)&pDirObj); if(FAILED(hres)) return ADSIToWMIErrorCodes(hres); // **** copy policy obj into AD hres = Som_CIMToAD(pInst, pDirObj, lFlags); if(FAILED(hres)) { if((HRESULT)0x8007200a == hres) ERRORTRACE((LOG_ESS, "POLICMAN: Active Directory Schema for MSFT_SomFilter is invalid/missing\n")); return ADSIToWMIErrorCodes(hres); } } catch(long hret) { hres = ADSIToWMIErrorCodes(hret); ERRORTRACE((LOG_ESS, "POLICMAN: Translation of Policy object from WMI to AD generated HRESULT 0x%08X\n", hres)); } catch(wchar_t *swErrString) { ERRORTRACE((LOG_ESS, "POLICMAN: Caught Exception: %S\n", swErrString)); hres = WBEM_E_FAILED; } catch(...) { ERRORTRACE((LOG_ESS, "POLICMAN: Caught unknown Exception\n")); hres = WBEM_E_FAILED; } } if(FAILED(hres) && pErrorObject) { if(FAILED(pResponseHandler->SetStatus(0,hres, NULL, pErrorObject))) ERRORTRACE((LOG_ESS, "POLICMAN: could not set return status\n")); } else { // **** indicate return status pInst->Get(L"__RELPATH", 0, &vRelPath, NULL, NULL); if(FAILED(pResponseHandler->SetStatus(0,hres, vRelPath.bstrVal, NULL))) ERRORTRACE((LOG_ESS, "POLICMAN: could not set return status\n")); } if (pErrorObject) pErrorObject->Release(); } CoRevertToSelf(); } return hres; } STDMETHODIMP CPolicySOM::XProvider::DeleteInstanceAsync( /* [in] */ const BSTR ObjectPath, /* [in] */ long lFlags, /* [in] */ IWbemContext __RPC_FAR *pCtx, /* [in] */ IWbemObjectSink __RPC_FAR *pResponseHandler) { HRESULT hres = WBEM_S_NO_ERROR, hres2 = WBEM_S_NO_ERROR; CComPtr pADsContainer; CComPtr pDisp; CComPtr pDelObj; VARIANT *pvDomain = NULL, *pvkeyID = NULL; ParsedObjectPath *pParsedObjectPath = NULL; // **** impersonate client hres = CoImpersonateClient(); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "POLICMAN: (CoImpersonateClient) could not assume callers permissions, 0x%08X\n",hres)); hres = WBEM_E_ACCESS_DENIED; } else { // **** Check arguments if(ObjectPath == NULL || pResponseHandler == NULL) { ERRORTRACE((LOG_ESS, "POLICMAN: object handle and/or return status object are NULL\n")); hres = WBEM_E_INVALID_PARAMETER; } else { // **** parse object path CObjectPathParser ObjPath(e_ParserAcceptRelativeNamespace); if((ObjPath.NoError != ObjPath.Parse(ObjectPath, &pParsedObjectPath)) || (0 != _wcsicmp(g_bstrClassSom, pParsedObjectPath->m_pClass)) || (2 != pParsedObjectPath->m_dwNumKeys)) { ERRORTRACE((LOG_ESS, "POLICMAN: Parse error for object: %S\n", ObjectPath)); hres = WBEM_E_INVALID_QUERY; } else { int x; for(x = 0; x < pParsedObjectPath->m_dwNumKeys; x++) { if(0 == _wcsicmp((*(pParsedObjectPath->m_paKeys + x))->m_pName, g_bstrDomain)) pvDomain = &((*(pParsedObjectPath->m_paKeys + x))->m_vValue); else if(0 == _wcsicmp((*(pParsedObjectPath->m_paKeys + x))->m_pName, g_bstrID)) pvkeyID = &((*(pParsedObjectPath->m_paKeys + x))->m_vValue); } CComBSTR bstrDomain = (pvDomain->vt == VT_BSTR ? pvDomain->bstrVal : NULL); pADsContainer.Attach(m_pObject->GetADServices(bstrDomain, hres)); if((FAILED(hres)) || (pADsContainer == NULL)) { ERRORTRACE((LOG_ESS, "POLICMAN: Could not find domain: %S\n", V_BSTR(pvDomain))); hres = ADSIToWMIErrorCodes(hres); } else { // **** get pointer to instance in AD CComBSTR bstrKeyID(L"CN="); bstrKeyID.Append(V_BSTR(pvkeyID)); hres = pADsContainer->GetObject(g_bstrADClassSom, bstrKeyID, &pDisp); if(FAILED(hres)) { hres = ADSIToWMIErrorCodes(hres); ERRORTRACE((LOG_ESS, "POLICMAN: (IADsContainer::GetObject) could not get object in AD %S, 0x%08X\n", V_BSTR(pvkeyID), hres)); } else { hres = pDisp->QueryInterface(IID_IADsDeleteOps, (void **)&pDelObj); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "POLICMAN: (IDispatch::QueryInterface) could not get IID_IADsDeleteOps interface on object\n")); } else { // **** delete the instance and all its children in AD hres = pDelObj->DeleteObject(0); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "POLICMAN: (IADsDeleteOps::DeleteObject) could not delete object (0x%08X)\n", hres)); hres = WBEM_E_ACCESS_DENIED; } } } } } ObjPath.Free(pParsedObjectPath); hres2 = pResponseHandler->SetStatus(0,hres, NULL, NULL); if(FAILED(hres2)) { ERRORTRACE((LOG_ESS, "POLICMAN: could not set return status\n")); if(SUCCEEDED(hres)) hres = hres2; } } CoRevertToSelf(); } return hres; } STDMETHODIMP CPolicySOM::XProvider::ExecQueryAsync( /* [in] */ const BSTR QueryLanguage, /* [in] */ const BSTR Query, /* [in] */ long lFlags, /* [in] */ IWbemContext __RPC_FAR *pCtx, /* [in] */ IWbemObjectSink __RPC_FAR *pResponseHandler) { HRESULT hres = WBEM_E_FAILED; CComPtr pNameSpace; hres = CoImpersonateClient(); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "POLICMAN: (CoImpersonateClient) could not assume callers permissions, 0x%08X\n",hres)); hres = WBEM_E_ACCESS_DENIED; } else { pNameSpace.Attach(m_pObject->GetWMIServices()); hres = ExecuteWQLQuery(m_pObject, Query, pResponseHandler, pNameSpace, g_bstrADClassSom, Som_ADToCIM); hres = ADSIToWMIErrorCodes(hres); if(pResponseHandler != NULL) pResponseHandler->SetStatus(0, hres, 0, 0); } CoRevertToSelf(); return hres; } STDMETHODIMP CPolicySOM::XProvider::ExecMethodAsync( /* [in] */ const BSTR strObjectPath, /* [in] */ const BSTR strMethodName, /* [in] */ long lFlags, /* [in] */ IWbemContext __RPC_FAR *pCtx, /* [in] */ IWbemClassObject __RPC_FAR *pInParams, /* [in] */ IWbemObjectSink __RPC_FAR *pResponseHandler) { HRESULT hr = WBEM_E_FAILED; #ifdef TIME_TRIALS EvaluateTimer.Start(StopWatch::ProviderTimer); #endif enum WhichMethod {Eval, BatchEval}; WhichMethod whichMethod; // check for valid method name if (_wcsicmp(strMethodName, L"Evaluate") == 0) whichMethod = Eval; else if (_wcsicmp(strMethodName, L"BatchEvaluate") == 0) whichMethod = BatchEval; else return WBEM_E_INVALID_METHOD; // **** impersonate client for security hr = CoImpersonateClient(); if (FAILED(hr)) return hr; // retrieve target object CComPtr pService; pService.Attach(m_pObject->GetWMIServices()); if (pService == NULL) hr = WBEM_E_FAILED; else { CComQIPtr pObj; #ifdef TIME_TRIALS EvaluateTimer.Start(StopWatch::WinMgmtTimer); #endif if (SUCCEEDED(hr = pService->GetObject(strObjectPath, WBEM_FLAG_RETURN_WBEM_COMPLETE, pCtx, &pObj, NULL))) { #ifdef TIME_TRIALS EvaluateTimer.Start(StopWatch::ProviderTimer); #endif // retreive class & output param object CComQIPtr pOurClass; if (NULL == (pOurClass = GetSomClass())) hr = WBEM_E_FAILED; else { CComQIPtr pOutClass; if (SUCCEEDED(hr = pOurClass->GetMethod(strMethodName, 0, NULL, &pOutClass))) { CComQIPtr pOutInstance; if (SUCCEEDED(pOutClass->SpawnInstance(0, &pOutInstance))) { if (whichMethod == Eval) hr = Evaluate(pObj, pOutInstance); else if (whichMethod == BatchEval) hr = BatchEvaluate(pInParams, pOutInstance, pService); else hr = WBEM_E_INVALID_METHOD; if (SUCCEEDED(hr)) hr = pResponseHandler->Indicate(1, &pOutInstance); } } } } else hr = WBEM_E_NOT_FOUND; } #ifdef TIME_TRIALS EvaluateTimer.Stop(); EvaluateTimer.LogResults(); EvaluateTimer.Reset(); // for next time! #endif // difficult call - do we put this before or after we take the timestamp? pResponseHandler->SetStatus(0,hr,NULL, NULL); CoRevertToSelf(); return hr; }