#include #include #include #include #include #include #include #include #include #include "WMI_CSE.h" #include #include #include #include #include #include #include #include #include #include #include BSTR RSOP_WMIGPOName = NULL; BSTR RSOP_AppliedPolicyTemplateName = NULL; BSTR RSOP_AppliedPolicyTypeName = NULL; BSTR RSOP_WmiTargetObjectName = NULL; BSTR MSFT_PolicyTemplateName = NULL; BSTR MSFT_WMIGPOName = NULL; BSTR MSFT_AppliedPolicyTemplateName = NULL; BSTR MSFT_AppliedPolicyTypeName = NULL; BSTR MSFT_WmiTargetObjectName = NULL; const WCHAR* DsContextName = L"DsContext"; const WCHAR* DsLocalValue = L"Local"; // switch to enable async processing // if re-enabled: must fix ProcessGroupPolicyEx // and the dll registration to indicate we do async processing //#define ASYNCH_ENABLED // wrapper for PutInstance // jumps through some extra hoops to make sure that the class def is correct HRESULT PutInstance(IWbemServices* pNamespace, IWbemClassObject* pObj) { DEBUGTRACE((LOG_ESS, "CSE: PutInstance(Long way)\n")); HRESULT hr = WBEM_E_FAILED; VARIANT vClassName; VariantInit(&vClassName); if (SUCCEEDED(hr = pObj->Get(L"__CLASS",0, &vClassName, NULL, NULL))) { IWbemClassObject* pNewClass = NULL; IWbemClassObject* pNewObj = NULL; CReleaseMe r1(pNewClass); CReleaseMe r2(pNewObj); if (SUCCEEDED(hr = pNamespace->GetObject(vClassName.bstrVal, 0, NULL, &pNewClass, NULL))) { if (SUCCEEDED(hr = pNewClass->SpawnInstance(0, &pNewObj))) { // got all the pieces, walk the properties & transfer them. pObj->BeginEnumeration(WBEM_FLAG_NONSYSTEM_ONLY); BSTR pPropName = NULL; VARIANT vProp; VariantInit(&vProp); while (pObj->Next(0, &pPropName, &vProp, NULL, NULL) != WBEM_S_NO_MORE_DATA) { pNewObj->Put(pPropName, 0, &vProp, NULL); SysFreeString(pPropName); pPropName = NULL; VariantClear(&vProp); } pObj->EndEnumeration(); if (FAILED(hr = pNamespace->PutInstance(pNewObj, WBEM_FLAG_USE_AMENDED_QUALIFIERS | WBEM_FLAG_CREATE_OR_UPDATE, NULL, NULL))) ERRORTRACE((LOG_ESS, "CSE: Failed to put new object, %0x08X", hr)); } else ERRORTRACE((LOG_ESS, "CSE: Failed to spawn instance of new class, %0x08X", hr)); } else ERRORTRACE((LOG_ESS, "CSE: Failed to retrieve new class, 0x%08X\n", hr)); } DEBUGTRACE((LOG_ESS, "CSE: PutInstance(Long way) returning 0x%08X on %S\n", hr, vClassName.bstrVal)); SysFreeString(vClassName.bstrVal); return hr; } HRESULT CSEInitGlobalNames() { HRESULT hr = WBEM_S_NO_ERROR; RSOP_WMIGPOName = SysAllocString(L"RSOP_WMIGPOPolicySetting"); RSOP_AppliedPolicyTemplateName = SysAllocString(L"RSOP_AppliedPolicyTemplate"); RSOP_AppliedPolicyTypeName = SysAllocString(L"RSOP_AppliedPolicyType"); RSOP_WmiTargetObjectName = SysAllocString(L"RSOP_WmiTargetObject"); MSFT_WMIGPOName = SysAllocString(L"MSFT_WMIGPOPolicySetting"); MSFT_PolicyTemplateName = SysAllocString(L"MSFT_PolicyTemplate"); MSFT_AppliedPolicyTemplateName = SysAllocString(L"MSFT_AppliedPolicyTemplate"); MSFT_AppliedPolicyTypeName = SysAllocString(L"MSFT_AppliedPolicyType"); MSFT_WmiTargetObjectName = SysAllocString(L"MSFT_WmiTargetObject"); if ( (RSOP_WMIGPOName == NULL) || (RSOP_AppliedPolicyTemplateName == NULL) || (RSOP_WmiTargetObjectName == NULL) || (RSOP_AppliedPolicyTypeName == NULL) || (MSFT_PolicyTemplateName == NULL) || (MSFT_WMIGPOName == NULL) || (MSFT_AppliedPolicyTemplateName == NULL) || (MSFT_AppliedPolicyTypeName == NULL) || (MSFT_WmiTargetObjectName == NULL) ) hr = WBEM_E_OUT_OF_MEMORY; return hr; } void ReleaseGlobalNames() { if (RSOP_WMIGPOName) SysFreeString(RSOP_WMIGPOName); if (RSOP_AppliedPolicyTemplateName) SysFreeString(RSOP_AppliedPolicyTemplateName); if (RSOP_WmiTargetObjectName) SysFreeString(RSOP_WmiTargetObjectName); if (RSOP_AppliedPolicyTypeName) SysFreeString(RSOP_AppliedPolicyTypeName); if (MSFT_PolicyTemplateName) SysFreeString(MSFT_PolicyTemplateName); if (MSFT_AppliedPolicyTemplateName) SysFreeString(MSFT_AppliedPolicyTemplateName); if (MSFT_AppliedPolicyTypeName) SysFreeString(MSFT_AppliedPolicyTypeName); if (MSFT_WmiTargetObjectName) SysFreeString(MSFT_WmiTargetObjectName); if (MSFT_WMIGPOName) SysFreeString(MSFT_WMIGPOName); } // todo: expand this DWORD HResultToWinError(HRESULT hr) { if (FAILED(hr)) return ERROR_FUNCTION_FAILED; else return ERROR_SUCCESS; } HRESULT GetNamespaceAndSetBlanket( BSTR bstr, IWbemServices*& pNamespace, bool bInProc ) { HRESULT hr = GetNamespace(bstr, pNamespace, bInProc ); if ( FAILED(hr) ) { return hr; } return CoSetProxyBlanket( pNamespace, RPC_C_AUTHN_DEFAULT, RPC_C_AUTHZ_DEFAULT, COLE_DEFAULT_PRINCIPAL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_DEFAULT ); } HRESULT GetPolicyNamespace(IWbemServices*& pPolicyNamespace) { HRESULT hr; BSTR bstr = SysAllocString(L"\\\\.\\ROOT\\POLICY"); if (bstr) { hr = GetNamespaceAndSetBlanket(bstr, pPolicyNamespace, false); SysFreeString(bstr); } else hr = WBEM_E_OUT_OF_MEMORY; if (FAILED(hr)) ERRORTRACE((LOG_ESS, "CSE: Failed to retrieve policy namespace (0x%08X)\n", hr)); return hr; } HRESULT GetHistoryNamespace(IWbemServices*& pHistoryNamespace) { HRESULT hr; BSTR bstr = SysAllocString(L"\\\\.\\ROOT\\POLICY\\HISTORY"); if (bstr) hr = GetNamespaceAndSetBlanket(bstr, pHistoryNamespace, false); else hr = WBEM_E_OUT_OF_MEMORY; if (FAILED(hr)) ERRORTRACE((LOG_ESS, "CSE: Failed to retrieve history namespace \"%S\"(0x%08X)\n", bstr, hr)); if (bstr) SysFreeString(bstr); return hr; } // compile classes from fname into given namespace // assumes that fname is local to wbem directory HRESULT EnsureSchema(IWbemServices* pNamespace, WCHAR* fname) { // prepare file name WCHAR fpath[MAX_PATH +1]; GetSystemDirectory(fpath, MAX_PATH); wcscat(fpath, L"\\wbem\\"); wcscat(fpath, fname); // grab the compiler HRESULT hr; IMofCompiler* pCompiler = NULL; hr = CoCreateInstance(CLSID_MofCompiler, NULL, CLSCTX_INPROC_SERVER, IID_IMofCompiler, (void**)&pCompiler); if (SUCCEEDED(hr)) { // see if we can't figure out the namespace name // will grab a system class & fish out the namespace name BSTR name; if (name = SysAllocString(L"__NAMESPACE")) { IWbemClassObject* pClass = NULL; if (SUCCEEDED(hr = pNamespace->GetObject(name, 0, NULL, &pClass, NULL))) { VARIANT v; VariantInit(&v); if (SUCCEEDED(hr = pClass->Get(L"__namespace", 0, &v, NULL, NULL))) { WBEM_COMPILE_STATUS_INFO info; DEBUGTRACE((LOG_ESS, "CSE Compiling %S to %S\n", fname, v.bstrVal)); // ready, set, compile! hr = pCompiler->CompileFile(fpath, v.bstrVal, NULL, NULL, NULL, WBEM_FLAG_DONT_ADD_TO_LIST, WBEM_FLAG_UPDATE_FORCE_MODE, 0, &info); if (FAILED(hr)) ERRORTRACE((LOG_ESS, "CSE: mof compilation failed, phase: %l, line %l\n", info.lPhaseError, info.FirstLine)); VariantClear(&v); } else { ERRORTRACE((LOG_ESS, "Could not determine namespace 0x%08X\n",hr)); } pClass->Release(); } SysFreeString(name); } else hr = WBEM_E_OUT_OF_MEMORY; pCompiler->Release(); } if (FAILED(hr)) ERRORTRACE((LOG_ESS, "CSE: Failed EnsureSchema (%S) (0x%08X)\n", fpath, hr)); return hr; }; // compile the wmi rsop objects into the namespace HRESULT EnsureRSOPSchema(IWbemServices* pNamespace) { DEBUGTRACE((LOG_ESS, "CSE: EnsureRSOPSchema\n")); // grab a random class to determine whether our schema has been compiled yet. IWbemClassObject* pRandomClass = NULL; if (SUCCEEDED(pNamespace->GetObject(RSOP_WMIGPOName, WBEM_FLAG_DIRECT_READ, NULL, &pRandomClass, NULL))) { DEBUGTRACE((LOG_ESS, "CSE: EnsureRSOPSchema found RSOP_WMIGPO, no compilation\n")); pRandomClass->Release(); return WBEM_S_NO_ERROR; } else { DEBUGTRACE((LOG_ESS, "CSE: EnsureRSOPSchema did not find RSOP_WMIGPO, will compile mof\n")); HRESULT hr = EnsureSchema(pNamespace, L"WMI_RSOP.MOF"); if (FAILED(pNamespace->GetObject(RSOP_WMIGPOName, WBEM_FLAG_DIRECT_READ, NULL, &pRandomClass, NULL))) { ERRORTRACE((LOG_ESS, "CSE: cannot find RSOP_WMIGPO after successful mof compilation!\n")); return WBEM_E_FAILED; } else { DEBUGTRACE((LOG_ESS, "CSE: found RSOP_WMIGPO after successful mof compilation!\n"));; pRandomClass->Release(); } return hr; } } HRESULT EnsurePolicySchema(IWbemServices* pNamespace) { // grab a random class to determine whether our schema has been compiled yet. IWbemClassObject* pRandomClass = NULL; if (SUCCEEDED(pNamespace->GetObject(MSFT_PolicyTemplateName, WBEM_FLAG_DIRECT_READ, NULL, &pRandomClass, NULL))) { pRandomClass->Release(); return WBEM_S_NO_ERROR; } else return EnsureSchema(pNamespace, L"WMIPolicy.mof"); } // given ds path // creates MSFT_WMIGPO.DsPath="path" inline void MakeGPOPath(const WCHAR* pDsPath, WCHAR* pBuf) { swprintf(pBuf, WMIGPO_GETOBJECT_TEMPLATE, pDsPath); } // called by FixupPath, does actual parse & replace // changes data in pParsedObjectPath // alloc's bstr for return (with luck...) HRESULT DoPathEdit(ParsedObjectPath* pParsedObjectPath, DWORD nKey, BSTR& newPath) { DEBUGTRACE((LOG_ESS, "CSE: DoPathEdit\n")); HRESULT hr = WBEM_E_FAILED; PDOMAIN_CONTROLLER_INFO pInfo; if (0 == DsGetDcName(NULL, NULL, NULL, NULL, DS_RETURN_DNS_NAME, &pInfo)) { if (pInfo->DomainName) { // safe copy "Domain" has fewer chars than "DsContext" wcscpy(pParsedObjectPath->m_paKeys[nKey]->m_pName, L"Domain"); // this will be freed externally via CObjectPathParser::Free BSTR valueName; if (valueName = SysAllocString(pInfo->DomainName)) { SysFreeString(pParsedObjectPath->m_paKeys[nKey]->m_vValue.bstrVal); pParsedObjectPath->m_paKeys[nKey]->m_vValue.bstrVal = valueName; CObjectPathParser objPath(e_ParserAcceptRelativeNamespace); int nRet; WCHAR* tempNewPath; nRet = objPath.Unparse(pParsedObjectPath, &tempNewPath); if (nRet == CObjectPathParser::OutOfMemory) hr = WBEM_E_OUT_OF_MEMORY; else if (nRet == CObjectPathParser::NoError) { if (newPath = SysAllocString(tempNewPath)) hr = WBEM_S_NO_ERROR; delete[] tempNewPath; } else hr = WBEM_E_FAILED; } else hr = WBEM_E_OUT_OF_MEMORY; } NetApiBufferFree(pInfo); } DEBUGTRACE((LOG_ESS, "CSE: DoPathEdit returning 0x%08X (%S)\n", hr, newPath)); return hr; } // support for legacy versions where the path may contain DsContext = LOCAL // bstr may be different upon exit [IN OUT] // returns success if finds DsContext = LOCAL // returns WBEM_E_INVALID_PATH if DsContext = GLOBAL HRESULT FixupPath(BSTR& path) { DEBUGTRACE((LOG_ESS, "CSE: Fixup Path %S\n", path)); HRESULT hr = WBEM_E_INVALID_OBJECT_PATH; enum ParseResults {GoodPath, BadPath, FixablePath}; ParseResults parseResult = BadPath; DWORD whichKey = 0; CObjectPathParser objPath(e_ParserAcceptRelativeNamespace); ParsedObjectPath* pParsedObjectPath = NULL; if ((objPath.NoError == objPath.Parse(path, &pParsedObjectPath))) { parseResult = GoodPath; for (DWORD i = 0; i < pParsedObjectPath->m_dwNumKeys; i++) if (_wcsicmp(DsContextName, pParsedObjectPath->m_paKeys[i]->m_pName) == 0) { if ((pParsedObjectPath->m_paKeys[i]->m_vValue.vt == VT_BSTR) && (pParsedObjectPath->m_paKeys[i]->m_vValue.bstrVal != NULL) && (_wcsicmp(DsLocalValue, pParsedObjectPath->m_paKeys[i]->m_vValue.bstrVal) == 0) ) { parseResult = FixablePath; whichKey = i; } else parseResult = BadPath; break; } } switch (parseResult) { case GoodPath: hr = WBEM_S_NO_ERROR; break; case BadPath: hr = WBEM_E_INVALID_OBJECT_PATH; break; case FixablePath: { BSTR newPath = NULL; if (SUCCEEDED(hr = DoPathEdit(pParsedObjectPath, whichKey, newPath))) { SysFreeString(path); path = newPath; } } } if (pParsedObjectPath) objPath.Free(pParsedObjectPath); DEBUGTRACE((LOG_ESS, "CSE: Fixup Path returning 0x%08X, (%S)\n", hr, path)); return hr; } // given ds path of MSFT_WMIGPO object // retrieves paths of templates packed in variant HRESULT GetPolicyTemplatePaths(IWbemServices* pPolicyNamespace, const WCHAR* pWMIGPOPath, VARIANT& v) { HRESULT hr; // get MSFT_WMIGPO WCHAR pathBuf[WMIGPO_GETOBJECT_STRLEN] = L""; MakeGPOPath(pWMIGPOPath, pathBuf); IWbemClassObject* pWMIGPO = NULL; BSTR bstrPath = SysAllocString(pathBuf); if (NULL == bstrPath) return WBEM_E_OUT_OF_MEMORY; else { hr = FixupPath(bstrPath); if (FAILED(hr)) return hr; if (FAILED(hr = pPolicyNamespace->GetObject(bstrPath, WBEM_FLAG_RETURN_WBEM_COMPLETE, NULL, &pWMIGPO, NULL))) ERRORTRACE((LOG_ESS, "CSE: Failed GetObject(%S) 0x%08X\n", pathBuf, hr)); else { if (FAILED(hr = pWMIGPO->Get(L"PolicyTemplate", 0, &v, NULL, NULL))) ERRORTRACE((LOG_ESS, "CSE: Failed MSFT_WMIGPO->Get(PolicyTemplate) (0x%08X)\n", hr)); else { if (v.vt != (VT_BSTR | VT_ARRAY)) { hr = WBEM_E_INVALID_PARAMETER; ERRORTRACE((LOG_ESS, "CSE: MSFT_WMIGPO \"%S\" contains invalid path\n", pWMIGPOPath)); VariantClear(&v); } } // if got policy template reference pWMIGPO->Release(); } // if Got GPO Object SysFreeString(bstrPath); } return hr; } // given ds history path of RSOP_PolicyObject in history // retrieves paths of templates packed in variant HRESULT GetPolicyTemplatePathsFromHistory(IWbemServices* pHistoryNamespace, const WCHAR* pPOPath, IWbemClassObject** pPO, VARIANT& v) { HRESULT hr; // get MSFT_WMIGPO // IWbemClassObject* pPO = NULL; BSTR bstrPath = SysAllocString(pPOPath); if (!bstrPath) return WBEM_E_OUT_OF_MEMORY; if (FAILED(hr = pHistoryNamespace->GetObject(bstrPath, WBEM_FLAG_RETURN_WBEM_COMPLETE, NULL, pPO, NULL))) ERRORTRACE((LOG_ESS, "CSE: Failed GetObject(%S) 0x%08X\n", bstrPath, hr)); else { VariantInit(&v); if (FAILED(hr = (*pPO)->Get(L"templates", 0, &v, NULL, NULL))) ERRORTRACE((LOG_ESS, "CSE: Failed MSFT_WMIGPOPolicySetting->Get(templates) (0x%08X)\n", hr)); else { if (v.vt != (VT_BSTR | VT_ARRAY)) { hr = WBEM_E_INVALID_PARAMETER; ERRORTRACE((LOG_ESS, "CSE: MSFT_WMIGPOPolicySetting \"%S\" contains invalid path\n", pPOPath)); VariantClear(&v); } } // if got policy template reference // pPO->Release(); } // if Got GPO Object if (bstrPath) SysFreeString(bstrPath); return hr; } // given ds path of MSFT_WMIGPO object, retrieves // associated policy Templates, stuffs 'em all into the template map HRESULT GetPolicyTemplates(IWbemServices* pPolicyNamespace, const WCHAR* pPath, TemplateMap& policies, IWbemServices* pRSOPNamespace, IWbemClassObject* pRsopWMIGPOClass, IWbemClassObject* pRsopTemplateClass, IWbemServices* pHistoryNamespace, IWbemClassObject* pMsftWMIGPOClass, IWbemClassObject* pMsftTemplateClass) { DEBUGTRACE((LOG_ESS, "CSE: GetPolicyTemplate\n")); HRESULT hr = WBEM_S_NO_ERROR; BSTR bstr = NULL; IWbemClassObject *pTemplate = NULL; VARIANT vPaths; VariantInit(&vPaths); IWbemClassObject* pRsopWMIGPOObj = NULL; CReleaseMe relWmiGpo(pRsopWMIGPOObj); IWbemClassObject* pMsftWMIGPOObj = NULL; CReleaseMe relOtherWmiGpo(pMsftWMIGPOObj); if (pRSOPNamespace || pHistoryNamespace) { // if we're writing to either, we will want both of these VARIANT vPrecedence; VariantInit(&vPrecedence); vPrecedence.vt = VT_I4; vPrecedence.lVal = 1; VARIANT vID; VariantInit(&vID); vID.vt = VT_BSTR; vID.bstrVal = SysAllocString(pPath); CSysFreeMe freeTheBeast(vID.bstrVal); if (pRSOPNamespace) { if (FAILED(hr = pRsopWMIGPOClass->SpawnInstance(0, &pRsopWMIGPOObj))) { ERRORTRACE((LOG_ESS, "CSE: pRsopWMIGPOClass->SpawnInstance failed, 0x%08X\n", hr)); return hr; } else { pRsopWMIGPOObj->Put(L"precedence", 0, &vPrecedence, NULL); pRsopWMIGPOObj->Put(L"GPOID", 0, &vID, NULL); pRsopWMIGPOObj->Put(L"id", 0, &vID, NULL); } } if (pHistoryNamespace) { if (FAILED(hr = pMsftWMIGPOClass->SpawnInstance(0, &pMsftWMIGPOObj))) { ERRORTRACE((LOG_ESS, "CSE: pMsftWMIGPOClass->SpawnInstance failed, 0x%08X\n", hr)); return hr; } else { pMsftWMIGPOObj->Put(L"precedence", 0, &vPrecedence, NULL); pMsftWMIGPOObj->Put(L"GPOID", 0, &vID, NULL); pMsftWMIGPOObj->Put(L"id", 0, &vID, NULL); } } } if (SUCCEEDED(hr = GetPolicyTemplatePaths(pPolicyNamespace, pPath, vPaths))) { SafeArray paths(&vPaths); SAFEARRAYBOUND arrayBounds; arrayBounds.lLbound = 0; arrayBounds.cElements = paths.Size(); SAFEARRAY* pRsopReferences = SafeArrayCreate(VT_BSTR, 1, &arrayBounds); if (pRsopReferences == NULL) return WBEM_E_OUT_OF_MEMORY; SAFEARRAY* pMsftReferences = SafeArrayCreate(VT_BSTR, 1, &arrayBounds); if (pMsftReferences == NULL) return WBEM_E_OUT_OF_MEMORY; for (long i = 0; i < paths.Size(); i++) { hr = FixupPath(paths[i]); if (FAILED(hr)) return hr; pTemplate = NULL; if (FAILED(hr = pPolicyNamespace->GetObject(paths[i], WBEM_FLAG_RETURN_WBEM_COMPLETE, NULL, &pTemplate, NULL))) { ERRORTRACE((LOG_ESS, "CSE: Failed to retrieve \"%S\", (0x%08X)\n", bstr, hr)); hr = WBEM_E_INVALID_PARAMETER; break; } else { CReleaseMe relTemplate1(pTemplate); VARIANT v; VariantInit(&v); if (SUCCEEDED(pTemplate->Get(L"targetPath", 0, &v, NULL, NULL))) { policies.Add(v.bstrVal, pTemplate); VariantClear(&v); } if (pRSOPNamespace || pHistoryNamespace) { VARIANT vUnk; VariantInit(&vUnk); vUnk.vt = VT_UNKNOWN; vUnk.punkVal = pTemplate; // no addref, no release VARIANT v; IWbemClassObject* pAppliedTemplate = NULL; if (pRSOPNamespace) { if (FAILED(hr = pRsopTemplateClass->SpawnInstance(0, &pAppliedTemplate))) return hr; else { CReleaseMe relTemplate2(pAppliedTemplate); pAppliedTemplate->Put(L"template", 0, &vUnk, NULL); VariantInit(&v); pTemplate->Get(L"__RELPATH", 0, &v, NULL, NULL); pAppliedTemplate->Put(L"templatePath", 0, &v, NULL); VariantClear(&v); pRSOPNamespace->PutInstance(pAppliedTemplate, WBEM_FLAG_CREATE_OR_UPDATE, NULL, NULL); pAppliedTemplate->Get(L"__RELPATH", 0, &v, NULL, NULL); SafeArrayPutElement(pRsopReferences, &i, v.bstrVal); VariantClear(&v); pAppliedTemplate = NULL; } } if (pHistoryNamespace) { if (FAILED(hr = pMsftTemplateClass->SpawnInstance(0, &pAppliedTemplate))) return hr; else { CReleaseMe relTemplate2(pAppliedTemplate); hr = pAppliedTemplate->Put(L"template", 0, &vUnk, NULL); VariantInit(&v); pTemplate->Get(L"__RELPATH", 0, &v, NULL, NULL); hr = pAppliedTemplate->Put(L"templatePath", 0, &v, NULL); VariantClear(&v); hr = pHistoryNamespace->PutInstance(pAppliedTemplate, WBEM_FLAG_CREATE_OR_UPDATE, NULL, NULL); if (FAILED(hr)) { ERRORTRACE((LOG_ESS, "Failed to put to history namespace 0x%08X\n",hr)); SafeArrayDestroy(pRsopReferences); SafeArrayDestroy(pMsftReferences); return hr; } pAppliedTemplate->Get(L"__RELPATH", 0, &v, NULL, NULL); SafeArrayPutElement(pMsftReferences, &i, v.bstrVal); VariantClear(&v); pAppliedTemplate = NULL; } } } } // end else } /// end for if(SUCCEEDED(hr)) { VARIANT vAgain; VariantInit(&vAgain); vAgain.vt = VT_ARRAY | VT_BSTR; if (pHistoryNamespace) { vAgain.parray = pMsftReferences; pMsftWMIGPOObj->Put(L"templates", 0, &vAgain, NULL); hr = pHistoryNamespace->PutInstance(pMsftWMIGPOObj, WBEM_FLAG_CREATE_OR_UPDATE, NULL, NULL); } if (pRSOPNamespace) { vAgain.parray = pRsopReferences; pRsopWMIGPOObj->Put(L"templates", 0, &vAgain, NULL); hr = pRSOPNamespace->PutInstance(pRsopWMIGPOObj, WBEM_FLAG_CREATE_OR_UPDATE, NULL, NULL); } VariantClear(&vPaths); } SafeArrayDestroy(pRsopReferences); SafeArrayDestroy(pMsftReferences); } DEBUGTRACE((LOG_ESS, "CSE: GetPolicyTemplate returning 0x%08X\n", hr)); return hr; } // TODO: enable undelete (via a sub-namespace?) // TODO: too darned deeply nested, break into smaller functions HRESULT DeleteOldPolicies(IWbemServices* pPolicyNamespace, IWbemServices *pRSOPNamespace, PGROUP_POLICY_OBJECT pGPOList, TemplateMap& newPolicies) { // no need to actually retrieve policies // if we've got said policy in history, we delete it // if it IS the last policy of that type, we delete target instance // if it is NOT the last policy, we stack up the remainders in the new policies HRESULT hr = WBEM_S_NO_ERROR; IWbemServices* pHistory; // TODO: this indents too deep. fix. PGROUP_POLICY_OBJECT pThisGPO; if (pThisGPO = pGPOList) if (SUCCEEDED(hr = GetHistoryNamespace(pHistory))) { try { do if (pThisGPO->lpDSPath) { DEBUGTRACE((LOG_ESS, "CSE: Deleting Policy '%S'\n\tcontaining path '%S'\n", pThisGPO->lpDisplayName, pThisGPO->lpDSPath)); // retrieve GPO from history QString pBuf(L"MSFT_WMIGPOPolicySetting.id='"); pBuf << pThisGPO->lpDSPath << L"'"; VARIANT vPaths; VariantInit(&vPaths); CComPtr pWMIGPO; if (SUCCEEDED(hr = GetPolicyTemplatePathsFromHistory(pHistory, pBuf, &pWMIGPO, vPaths))) { SafeArray paths(&vPaths); for (int i = 0; i < paths.Size(); i++) { IWbemClassObject* pDeadObject = NULL; // if it's not there, we've got no more work to do if (SUCCEEDED(pHistory->GetObject(paths[i], 0,NULL, &pDeadObject, NULL))) { // first delete from history... hr = pHistory->DeleteInstance(paths[i], 0, NULL, NULL); // **** next, delete from RSOP namespace if(NULL != pRSOPNamespace) { CComVariant vTemplatePath; QString path(RSOP_AppliedPolicyTemplateName); hr = pDeadObject->Get(L"TemplatePath", 0, &vTemplatePath, NULL, NULL); path << L".TemplatePath='" << vTemplatePath.bstrVal << L"'"; hr = pRSOPNamespace->DeleteInstance(path, 0, NULL, NULL); } VARIANT vID; VariantInit(&vID); VARIANT vObj; VariantInit(&vObj); // okay, we deleted it. // see if there are any left... // get the object out of the object, unless it objects if (SUCCEEDED(pDeadObject->Get(L"template", 0, &vObj, NULL, NULL))) { IWbemClassObject* pDeadObjectObject = NULL; vObj.punkVal->QueryInterface(IID_IWbemClassObject, (void**)&pDeadObjectObject); CReleaseMe relDeadDead(pDeadObjectObject); if (SUCCEEDED(hr = pDeadObjectObject->Get(L"TargetPath", 0, &vID, NULL, NULL))) { // TODO: fix for indeterminant buffer size... WCHAR query[1024]; swprintf(query, L"Select * from MSFT_AppliedPolicyTemplate where template.TargetPath = \"%S\"",vID.bstrVal); IEnumWbemClassObject *pEnum = NULL; bool bGotOne = false; if (SUCCEEDED(pHistory->ExecQuery(L"WQL", query, WBEM_FLAG_FORWARD_ONLY, NULL, &pEnum))) { HRESULT hrLoop; IWbemClassObject* pTemplate = NULL; ULONG uReturned; if (SUCCEEDED(hrLoop = pEnum->Next(WBEM_INFINITE, 1, &pTemplate, &uReturned)) && (hrLoop != WBEM_S_FALSE)) { // we're not doing the re-collection of non-deleted templates right now // reserve the right to put it back later bGotOne = true; // newPolicies.Add(vID.bstrVal, pTemplate); pTemplate->Release(); pTemplate = NULL; } pEnum->Release(); } // if there are no outstanding templates // we will want to delete the target object // TODO: better error handling if (!bGotOne) { CComVariant vNamespace; // **** delete target object if (SUCCEEDED(pDeadObjectObject->Get(L"TargetNamespace", 0, &vNamespace, NULL, NULL))) { IWbemServices *pTargetNamespace = NULL; if (SUCCEEDED(GetNamespace(vNamespace.bstrVal, pTargetNamespace, false))) if (FAILED(hr = pTargetNamespace->DeleteInstance(vID.bstrVal, 0, NULL, NULL))) ERRORTRACE((LOG_ESS, "CSE: Unable to delete %S 0x%08X\n", vID.bstrVal, hr)); if(NULL != pTargetNamespace) pTargetNamespace->Release(); } // **** delete MSFT_WMITargetObject associated with target object if(pHistory != NULL) { QString wmiTargetObject(MSFT_WmiTargetObjectName); wmiTargetObject << L".TargetPath='" << vID.bstrVal << L"'"; hr = pHistory->DeleteInstance(wmiTargetObject, 0, NULL, NULL); if(FAILED(hr)) ERRORTRACE((LOG_ESS, "CSE: Unable to delete %S 0x%08X\n", wmiTargetObject, hr)); } // **** delete RSOP_AppliedPolicyTemplate associated with target object if(pRSOPNamespace != NULL) { QString wmiTargetObject(RSOP_WmiTargetObjectName); wmiTargetObject << L".TargetPath='" << vID.bstrVal << L"'"; hr = pRSOPNamespace->DeleteInstance(wmiTargetObject, 0, NULL, NULL); if(FAILED(hr)) ERRORTRACE((LOG_ESS, "CSE: Unable to delete %S 0x%08X\n", wmiTargetObject, hr)); } } } VariantClear(&vID); } pDeadObject->Release(); } // }// end for // **** clean up MSFT_WMIGPOPolicySetting object VariantClear(&vPaths); hr = pHistory->DeleteInstance(pBuf, 0, NULL, NULL); if(FAILED(hr)) ERRORTRACE((LOG_ESS, "CSE: Unable to delete %S 0x%08X\n", pBuf, hr)); if(NULL != pRSOPNamespace) { QString RSOPpath(RSOP_WMIGPOName); RSOPpath << L".id='" << pThisGPO->lpDSPath << L"'"; hr = pRSOPNamespace->DeleteInstance(RSOPpath, 0, NULL, NULL); if(FAILED(hr)) ERRORTRACE((LOG_ESS, "CSE: Unable to delete %S 0x%08X\n", (wchar_t*)RSOPpath, hr)); } } // if (SUCCEEDED(hr = GetPolicyTemplatePaths(pPolicyNamespace, yada, yada } // if (pThisGPO->lpDSPath) while (pThisGPO = pThisGPO->pNext); } catch (...) { // here mostly to catch bad pointers in the list DEBUGTRACE((LOG_ESS, "CSE: caught exception: continuing\n")); hr = WBEM_E_CRITICAL_ERROR; } pHistory->Release(); } if (FAILED(hr)) ERRORTRACE((LOG_ESS, "CSE: DeleteOldPolicies failed: 0x%08X\n", hr)); return hr; } // retrieve policies associated with GPO list // policies returned as IWbemObjects, positive refcount HRESULT GetPolicyArray(IWbemServices* pPolicyNamespace, PGROUP_POLICY_OBJECT pGPOList, IWbemServices* pRSOPNamespace, IWbemServices* pHistoryNamespace, TemplateMap& policies) { HRESULT hr = WBEM_S_NO_ERROR; IWbemClassObject* pRsopWmiGpo = NULL; IWbemClassObject* pRsopTemplate = NULL; IWbemClassObject* pMsftWmiGpo = NULL; IWbemClassObject* pMsftTemplate = NULL; CReleaseMe relpRsopWmiGpo (pRsopWmiGpo ); CReleaseMe relpRsopTemplate(pRsopTemplate); CReleaseMe relpMsftWmiGpo (pMsftWmiGpo ); CReleaseMe relpMsftTemplate(pMsftTemplate); if (pRSOPNamespace) { hr = pRSOPNamespace->GetObject(RSOP_WMIGPOName, 0, NULL, &pRsopWmiGpo, NULL); if (FAILED(hr)) { ERRORTRACE((LOG_ESS, "CSE: Unable to retrieve RSOP wmigpo 0x%08X\n", hr)); return hr; } hr = pRSOPNamespace->GetObject(RSOP_AppliedPolicyTemplateName, 0, NULL, &pRsopTemplate, NULL); if (FAILED(hr)) { ERRORTRACE((LOG_ESS, "CSE: Unable to retrieve RSOP policy template 0x%08X\n", hr)); return hr; } } if (pHistoryNamespace) { hr = pHistoryNamespace->GetObject(MSFT_WMIGPOName, 0, NULL, &pMsftWmiGpo, NULL); if (FAILED(hr)) { ERRORTRACE((LOG_ESS, "CSE: Unable to retrieve History wmigpo 0x%08X\n", hr)); return hr; } hr = pHistoryNamespace->GetObject(MSFT_AppliedPolicyTemplateName, 0, NULL, &pMsftTemplate, NULL); if (FAILED(hr)) { ERRORTRACE((LOG_ESS, "CSE: Unable to retrieve History policy template 0x%08X\n", hr)); return hr; } } PGROUP_POLICY_OBJECT pThisGPO; if (pThisGPO = pGPOList) { try { do if (pThisGPO->lpDSPath) { DEBUGTRACE((LOG_ESS, "CSE: Retrieving Policy '%S'\n\tcontaining path '%S'\n", pThisGPO->lpDisplayName, pThisGPO->lpDSPath)); if (FAILED(hr = GetPolicyTemplates(pPolicyNamespace, pThisGPO->lpDSPath, policies, pRSOPNamespace, pRsopWmiGpo, pRsopTemplate, pHistoryNamespace, pMsftWmiGpo, pMsftTemplate ))) { ERRORTRACE((LOG_ESS, "Error retrieving policy pThisGPO->lpDSPath (0x%08X)\n", hr)); } } while (SUCCEEDED(hr) && (pThisGPO = pThisGPO->pNext)); } catch (...) { // here mostly to recover from bad pointers in the list... hr = WBEM_E_CRITICAL_ERROR; } } return hr; } // assuming that pTypeObj is a MSFT_PolicyType // PutClass's embedded class def'n // and PutInstance's embedded instances HRESULT SetTypeFromObj(IWbemServices* pTargetNamespace, IWbemClassObject* pTypeObj, IWbemClassObject** ppClassDef) { VARIANT vTypeType; VariantInit (&vTypeType); HRESULT hr = WBEM_E_FAILED; DEBUGTRACE((LOG_ESS, "CSE: SetTypeFromObj\n")); // do it for instances (may be types - class definitions!) if (SUCCEEDED(hr = pTypeObj->Get(L"InstanceDefinitions", 0, &vTypeType, NULL, NULL))) { if ((vTypeType.vt != VT_NULL) && (vTypeType.punkVal != NULL)) { SafeArray punks(&vTypeType); DEBUGTRACE((LOG_ESS, "CSE: Putting %d instance definitions\n", punks.Size())); for (int i = 0; i < punks.Size() && (SUCCEEDED(hr)); i++) { IWbemClassObject* pObj = NULL; if (punks[i] && SUCCEEDED(hr = punks[i]->QueryInterface(IID_IUnknown, (void**)&pObj) )) { CReleaseMe relativeUnknown(pObj); VARIANT v; VariantInit(&v); pObj->Get(L"__Genus", 0, &v, NULL, NULL); VARIANT vDebug; VariantInit(&vDebug); if (v.lVal == WBEM_GENUS_CLASS) { pObj->Get(L"__CLASS", 0, &vDebug, NULL, NULL); DEBUGTRACE((LOG_ESS, "CSE: Putting class %S\n", vDebug.bstrVal)); if (FAILED(hr = pTargetNamespace->PutClass(pObj, WBEM_FLAG_USE_AMENDED_QUALIFIERS | WBEM_FLAG_CREATE_OR_UPDATE | WBEM_FLAG_UPDATE_FORCE_MODE, NULL, NULL))) ERRORTRACE((LOG_ESS, "CSE: put class failed 0x%08X\n", hr)); } else { pObj->Get(L"__RELPATH", 0, &vDebug, NULL, NULL); DEBUGTRACE((LOG_ESS, "CSE: Putting instance %S\n", vDebug.bstrVal)); //if (FAILED(hr = pTargetNamespace->PutInstance(pObj, // WBEM_FLAG_USE_AMENDED_QUALIFIERS | WBEM_FLAG_CREATE_OR_UPDATE, // NULL, NULL))) if (FAILED(hr = PutInstance(pTargetNamespace, pObj))) ERRORTRACE((LOG_ESS, "CSE: put instance failed 0x%08X\n", hr)); } VariantClear(&vDebug); } } } VariantClear(&vTypeType); } // do it for class def'n if (SUCCEEDED(hr) && SUCCEEDED(hr = pTypeObj->Get(L"ClassDefinition", 0, &vTypeType, NULL, NULL))) { if ((vTypeType.vt != VT_NULL) && (vTypeType.punkVal != NULL)) { IWbemClassObject* pObj = NULL; if (SUCCEEDED(hr = vTypeType.punkVal->QueryInterface(IID_IWbemClassObject, (void**)&pObj))) { // nope - not gonna release it, wouldn't be prudent // we're gonna return it from the function instead //CReleaseMe relObject(pObj); *ppClassDef = pObj; VARIANT vDebug; VariantInit(&vDebug); pObj->Get(L"__CLASS", 0, &vDebug, NULL, NULL); DEBUGTRACE((LOG_ESS, "CSE: Putting ClassDefinition %S\n", vDebug.bstrVal)); VariantClear(&vDebug); if (FAILED(hr = pTargetNamespace->PutClass(pObj, WBEM_FLAG_USE_AMENDED_QUALIFIERS | WBEM_FLAG_CREATE_OR_UPDATE | WBEM_FLAG_UPDATE_FORCE_MODE, NULL, NULL))) ERRORTRACE((LOG_ESS, "CSE: put class failed 0x%08X\n", hr)); } } VariantClear(&vTypeType); } if (FAILED(hr)) ERRORTRACE((LOG_ESS, "CSE: SetTypeFromObj failed 0x%08X\n", hr)); return hr; } // retrieve template path from object // determine whether we've aleady got one // if not, retrieve one & put the class & all HRESULT EnsureType(IWbemServices* pTargetNamespace, IWbemServices* pPolicyNamespace, IWbemServices* pHistoryNamespace, IWbemClassObject* pTemplate, IWbemServices* pRsopNamespace, IWbemClassObject* pRsopObj, IWbemClassObject* pHistoryObj, IWbemClassObject** ppClassDef) { HRESULT hr = WBEM_E_FAILED; DEBUGTRACE((LOG_ESS, "CSE: EnsureType\n")); VARIANT vTypeName; VariantInit(&vTypeName); if (SUCCEEDED(pTemplate->Get(L"TargetType", 0, &vTypeName, NULL, NULL)) && (vTypeName.vt == VT_BSTR) && (vTypeName.bstrVal != NULL)) { DEBUGTRACE((LOG_ESS, "CSE: Target Type is %S\n", vTypeName.bstrVal)); WCHAR templ[] = L"MSFT_AppliedPolicyType.typePath='%s'"; WCHAR* pBuf = new WCHAR[wcslen(templ) + wcslen(vTypeName.bstrVal) +1]; if (!pBuf) return WBEM_E_OUT_OF_MEMORY; CDeleteMe delChars(pBuf); swprintf(pBuf, templ, vTypeName.bstrVal); BSTR typePath = SysAllocString(pBuf); if (!typePath) { ERRORTRACE((LOG_ESS, "CSE: Allocation failed on type path\n")); return WBEM_E_OUT_OF_MEMORY; } CSysFreeMe freeBeer(typePath); // record type in target object VARIANT vTypePath; VariantInit(&vTypePath); vTypePath.vt = VT_BSTR; vTypePath.bstrVal = typePath; if (pRsopObj) pRsopObj->Put(L"type", 0, &vTypePath, NULL); if (pHistoryObj) pHistoryObj->Put(L"type", 0, &vTypePath, NULL); IWbemClassObject* pTypeObj = NULL; CReleaseMe relative(pTypeObj); IWbemClassObject* pHistoryTypeObj = NULL; // check to see if we've got it in history // pRSOPTypeObj should be initialized in one of the if/else clauses if (pHistoryNamespace && SUCCEEDED(pHistoryNamespace->GetObject(typePath, 0, NULL, &pHistoryTypeObj, NULL))) { DEBUGTRACE((LOG_ESS, "CSE: found Target Type in history\n")); VARIANT v; VariantInit(&v); if (SUCCEEDED(pHistoryTypeObj->Get(L"type", 0, &v, NULL, NULL))) { IWbemClassObject* pType = NULL; if (SUCCEEDED(v.punkVal->QueryInterface(IID_IWbemClassObject, (void**)&pTypeObj))) { hr = SetTypeFromObj(pTargetNamespace, pTypeObj, ppClassDef); } } VariantClear(&v); } else { DEBUGTRACE((LOG_ESS, "CSE: retrieving Target Type from DS\n")); if (FAILED(hr = FixupPath(vTypeName.bstrVal))) return hr; if (SUCCEEDED(hr = pPolicyNamespace->GetObject(vTypeName.bstrVal, 0, NULL, &pTypeObj, NULL))) { hr = SetTypeFromObj(pTargetNamespace, pTypeObj, ppClassDef); IWbemClassObject* pTypeTypeType = NULL; // Keep a history object for next time if (pHistoryNamespace && SUCCEEDED(pHistoryNamespace->GetObject(MSFT_AppliedPolicyTypeName, 0, NULL, &pTypeTypeType, NULL))) { if (hr = SUCCEEDED(pTypeTypeType->SpawnInstance(0, &pHistoryTypeObj))) { VARIANT vObj; VariantInit(&vObj); vObj.vt = VT_UNKNOWN; vObj.punkVal = pTypeObj; VARIANT vPath; VariantInit(&vPath); if (SUCCEEDED(pTypeObj->Get(L"__RELPATH", 0, &vPath, NULL, NULL)) && SUCCEEDED(pHistoryTypeObj->Put(L"type", 0, &vObj, NULL)) && SUCCEEDED(pHistoryTypeObj->Put(L"typePath", 0, &vPath, NULL))) pHistoryNamespace->PutInstance(pHistoryTypeObj, WBEM_FLAG_CREATE_OR_UPDATE, NULL, NULL); else { // it's no good without the data, delete it now pHistoryTypeObj->Release(); pHistoryTypeObj = NULL; hr = WBEM_E_FAILED; } VariantClear(&vPath); } pTypeTypeType->Release(); } } } if (pHistoryTypeObj) pHistoryTypeObj->Release(); // make type available in RSOP if (pRsopNamespace && pTypeObj) { IWbemClassObject* pRSOPTypeClass = NULL; IWbemClassObject* pRSOPTypeObj = NULL; if (SUCCEEDED(pRsopNamespace->GetObject(RSOP_AppliedPolicyTypeName, 0, NULL, &pRSOPTypeClass, NULL))) { CReleaseMe rel45(pRSOPTypeClass); if (SUCCEEDED(pRSOPTypeClass->SpawnInstance(0, &pRSOPTypeObj))) { CReleaseMe rel46(pRSOPTypeObj); VARIANT vObj; VariantInit(&vObj); vObj.vt = VT_UNKNOWN; vObj.punkVal = pTypeObj; VARIANT vPath; VariantInit(&vPath); if (SUCCEEDED(pTypeObj->Get(L"__RELPATH", 0, &vPath, NULL, NULL)) && SUCCEEDED(pRSOPTypeObj->Put(L"type", 0, &vObj, NULL)) && SUCCEEDED(pRSOPTypeObj->Put(L"typePath", 0, &vPath, NULL))) pRsopNamespace->PutInstance(pRSOPTypeObj, WBEM_FLAG_CREATE_OR_UPDATE, NULL, NULL); VARIANT vRsopPath; VariantInit(&vRsopPath); pRSOPTypeObj->Get(L"__RELPATH", 0, &vRsopPath, NULL, NULL); pRsopObj->Put(L"policyType", 0, &vRsopPath, NULL); VariantClear(&vRsopPath); } } } VariantClear(&vTypeName); } else // retrieve type from namespace { DEBUGTRACE((LOG_ESS, "CSE: retrieving Target Class from Target Namespace\n")); VARIANT vTargetClassName; VariantInit(&vTargetClassName); if (SUCCEEDED(hr = pTemplate->Get(L"TargetClass", 0, &vTargetClassName, NULL, NULL))) hr = pTargetNamespace->GetObject(vTargetClassName.bstrVal, 0, NULL, ppClassDef, NULL); // don't release the class - we're returning it. VariantClear(&vTargetClassName); } DEBUGTRACE((LOG_ESS, "CSE: EnsureType returning 0x%08X\n", hr)); return hr; } // puts list into object // object is assumed to be the in-param object for the merge method HRESULT PrepMergeParam(SAFEARRAY* pList, IWbemClassObject* pMergeParam) { HRESULT hr; VARIANT v; VariantInit(&v); v.vt = VT_UNKNOWN | VT_ARRAY; if (SUCCEEDED(hr = SafeArrayCopy(pList, &v.parray))) hr = pMergeParam->Put(L"templateList", 0, &v, NULL); VariantClear(&v); return hr; } HRESULT PrepResolveParam(IWbemClassObject* pUnk, IWbemClassObject* pClassDef, IWbemClassObject* pResolveParam) { HRESULT hr; VARIANT v; VariantInit(&v); v.vt = VT_UNKNOWN; v.punkVal = pUnk; hr = pResolveParam->Put(L"template", 0, &v, NULL); if (SUCCEEDED(hr)) { v.punkVal = pClassDef; hr = pResolveParam->Put(L"classObject", 0, &v, NULL); } // no addref, no release... // VariantClear(&v); return hr; } HRESULT GetTemplateParams(IWbemServices* pPolicyNamespace, IWbemClassObject*& pMergeParam, IWbemClassObject*& pResolveParam) { HRESULT hr = WBEM_E_FAILED; BSTR bstrName = SysAllocString(L"MSFT_MergeablePolicyTemplate"); BSTR bstrMerge = SysAllocString(L"Merge"); BSTR bstrResolve = SysAllocString(L"Resolve"); if ((!bstrName) || (!bstrMerge) || (!bstrResolve)) hr = WBEM_E_OUT_OF_MEMORY; else { IWbemClassObject* pClass = NULL; if (SUCCEEDED(hr = pPolicyNamespace->GetObject(bstrName, 0, NULL, &pClass, NULL))) { if (SUCCEEDED(hr = pClass->GetMethod(bstrMerge, 0, &pMergeParam, NULL))) hr = pClass->GetMethod(L"Resolve", 0, &pResolveParam, NULL); pClass->Release(); } } if (bstrName) SysFreeString(bstrName); if (bstrMerge) SysFreeString(bstrMerge); if (bstrResolve) SysFreeString(bstrResolve); return hr; } // for each policyTemplate // determine whether we have associated type / MSFT_PolicyType // merge, write result, if pRSOPNamespace != NULL, result is written to rsop // if bDoItForReal is false - we are in planning mode: write to RSOP but *NOT* the target namespace or history // TODO: this is too long: cut. HRESULT ApplyPolicies(TemplateMap& policies, IWbemServices* pPolicyNamespace, IWbemServices* pRSOPNamespace, IWbemServices* pHistoryNamespace, bool bDoItForReal) { HRESULT hr = WBEM_S_NO_ERROR; // marching error recording for internal use HRESULT hrOverall = WBEM_S_NO_ERROR; // that which we will return to the outside world. // things we need to do RSOP IWbemClassObject* pRsopType = NULL; IWbemClassObject* pRsopTarget = NULL; // things we need to free RSOP things needed CReleaseMe relpRsopType (pRsopType ); CReleaseMe relpRsopTarget (pRsopTarget ); if ( pRSOPNamespace ) { hr = pRSOPNamespace->GetObject(RSOP_AppliedPolicyTypeName, 0, NULL, &pRsopType, NULL); if (FAILED(hr)) { ERRORTRACE((LOG_ESS, "CSE: Unable to retrieve RSOP_AppliedPolicyType 0x%08X\n", hr)); return WBEM_E_FAILED; } hr = pRSOPNamespace->GetObject(RSOP_WmiTargetObjectName, 0, NULL, &pRsopTarget, NULL); if (FAILED(hr)) { ERRORTRACE((LOG_ESS, "CSE: Unable to retrieve RSOP_WmiTargetObject 0x%08X\n", hr)); return WBEM_E_FAILED; } } // things we need to do History IWbemClassObject* pHistoryType = NULL; IWbemClassObject* pHistoryTarget = NULL; // things we need to free history things needed CReleaseMe relpHistoryType (pHistoryType ); CReleaseMe relpHistoryTarget (pHistoryTarget ); if ( pHistoryNamespace ) { hr = pHistoryNamespace->GetObject(MSFT_AppliedPolicyTypeName, 0, NULL, &pHistoryType, NULL); if (FAILED(hr)) { ERRORTRACE((LOG_ESS, "CSE: Unable to retrieve History type 0x%08X\n", hr)); return hr; } hr = pHistoryNamespace->GetObject(MSFT_WmiTargetObjectName, 0, NULL, &pHistoryTarget, NULL); if (FAILED(hr)) { ERRORTRACE((LOG_ESS, "CSE: Unable to retrieve History applied target object 0x%08X\n", hr)); return hr; } } // parameters for methods IWbemClassObject* pMergeParam = NULL; IWbemClassObject* pResolveParam = NULL; BSTR bstrTemplate = SysAllocString(L"MSFT_MergeablePolicyTemplate"); BSTR bstrMerge = SysAllocString(L"Merge"); BSTR bstrResolve = SysAllocString(L"Resolve"); CSysFreeMe freeTemplate(bstrTemplate); CSysFreeMe freeMerge(bstrMerge); CSysFreeMe freeResolve(bstrResolve); if ((bstrResolve == NULL) || (bstrTemplate == NULL) || (bstrMerge == NULL)) return WBEM_E_OUT_OF_MEMORY; if (FAILED(hr = GetTemplateParams(pPolicyNamespace, pMergeParam, pResolveParam))) return hr; int cookie = 0; SAFEARRAY* pList; while (pList = policies.GetTemplateList(cookie)) { // start building the RSOP Target obj IWbemClassObject* pRsopTargetObj = NULL; if (pRSOPNamespace) pRsopTarget->SpawnInstance(0, &pRsopTargetObj); CReleaseMe relTarget(pRsopTargetObj); // start building the History Target obj IWbemClassObject* pHistoryTargetObj = NULL; if (pHistoryNamespace) pHistoryTarget->SpawnInstance(0, &pHistoryTargetObj); CReleaseMe relHistoricalTarget(pHistoryTargetObj); // retrieve type object & namespace IWbemClassObject* pObj = NULL; IWbemClassObject* pClassDef = NULL; CReleaseMe relClassDef(pClassDef); IWbemServices* pTargetNamespace = NULL; long index = 0; // get first element, use for namespace name, etc. if (SUCCEEDED(hr = SafeArrayGetElement(pList, &index, &pObj))) { VARIANT vNamespaceName; VariantInit(&vNamespaceName); pObj->Get(L"TargetNamespace", 0, &vNamespaceName, NULL, NULL); if ((vNamespaceName.vt == VT_BSTR) && (vNamespaceName.bstrVal != NULL)) { if (SUCCEEDED(hr = GetNamespace(vNamespaceName.bstrVal, pTargetNamespace, false))) hr = EnsureType(pTargetNamespace, pPolicyNamespace, pHistoryNamespace, pObj, pRSOPNamespace, pRsopTargetObj, pHistoryTargetObj, &pClassDef); if (FAILED(hr)) { hrOverall = hr; ERRORTRACE((LOG_ESS, "CSE: EnsureType failed, 0x%08X, continuing\n", hr)); hr = WBEM_S_NO_ERROR; continue; } if (pRSOPNamespace && pRsopTargetObj) pRsopTargetObj->Put(L"TargetNamespace", 0, &vNamespaceName, NULL); if (pHistoryNamespace && pHistoryTargetObj) pHistoryTargetObj->Put(L"TargetNamespace", 0, &vNamespaceName, NULL); VariantClear(&vNamespaceName); } pObj->Release(); pObj = NULL; } else { ERRORTRACE((LOG_ESS, "ApplyPolicies: SafeArrayGetElement returned 0x%08X\n", hr)); return hr; } // stuff objects into history and/or RSOP long lUbound = 0; SafeArrayGetUBound(pList, 1, &lUbound); if (pRSOPNamespace) { // array for references to templates SAFEARRAY* pTemplateRefs = NULL; SAFEARRAYBOUND bounds = {lUbound, 0}; pTemplateRefs = SafeArrayCreate(VT_BSTR, 1, &bounds); if (!pTemplateRefs) return WBEM_E_OUT_OF_MEMORY; for (index = 0; index < lUbound; index++) { if (SUCCEEDED(hr = SafeArrayGetElement(pList, &index, &pObj))) { VARIANT vPath; VariantInit(&vPath); CReleaseMe relObj(pObj); pObj->Get(L"__RELPATH", 0, &vPath, NULL, NULL); WCHAR templ[] = L"RSOP_AppliedPolicyTemplate.templatePath='%s'"; WCHAR* pBuf = new WCHAR[wcslen(templ) + wcslen(vPath.bstrVal) +1]; if (!pBuf) return WBEM_E_OUT_OF_MEMORY; CDeleteMe delChars(pBuf); swprintf(pBuf, templ, vPath.bstrVal); BSTR path = SysAllocString(pBuf); SafeArrayPutElement(pTemplateRefs, &index, path); VariantClear(&vPath); SysFreeString(path); } } // stuff template array into rsop obj VARIANT vArray; VariantInit(&vArray); vArray.vt = VT_ARRAY | VT_BSTR; vArray.parray = pTemplateRefs; pRsopTargetObj->Put(L"templates", 0, &vArray, NULL); // don't need this anymore... SafeArrayDestroy(pTemplateRefs); } if (pHistoryNamespace) { // array for references to templates SAFEARRAY* pTemplateRefs = NULL; SAFEARRAYBOUND bounds = {lUbound, 0}; pTemplateRefs = SafeArrayCreate(VT_BSTR, 1, &bounds); if (!pTemplateRefs) return WBEM_E_OUT_OF_MEMORY; for (index = 0; index < lUbound; index++) { if (SUCCEEDED(hr = SafeArrayGetElement(pList, &index, &pObj))) { VARIANT vPath; VariantInit(&vPath); CReleaseMe relObj(pObj); pObj->Get(L"__RELPATH", 0, &vPath, NULL, NULL); WCHAR templ[] = L"MSFT_AppliedPolicyTemplate.templatePath='%s'"; WCHAR* pBuf = new WCHAR[wcslen(templ) + wcslen(vPath.bstrVal) +1]; if (!pBuf) return WBEM_E_OUT_OF_MEMORY; CDeleteMe delChars(pBuf); swprintf(pBuf, templ, vPath.bstrVal); BSTR path = SysAllocString(pBuf); SafeArrayPutElement(pTemplateRefs, &index, path); VariantClear(&vPath); SysFreeString(path); } } // stuff template array into history obj VARIANT vArray; VariantInit(&vArray); vArray.vt = VT_ARRAY | VT_BSTR; vArray.parray = pTemplateRefs; pHistoryTargetObj->Put(L"templates", 0, &vArray, NULL); // don't need this anymore... SafeArrayDestroy(pTemplateRefs); } // perform merge, resolve, stick resulting object into destination namespace(s) PrepMergeParam(pList, pMergeParam); IWbemClassObject* pOut = NULL; { BSTR x = NULL; pMergeParam->GetObjectText(0, &x); DEBUGTRACE((LOG_ESS, "CSE: Execute merge with input params: %S\n", x)); SysFreeString(x); } if (SUCCEEDED(hr = pPolicyNamespace->ExecMethod(bstrTemplate, bstrMerge, 0, NULL, pMergeParam, &pOut, NULL))) { VARIANT vOut; VariantInit(&vOut); if (SUCCEEDED(hr = pOut->Get(L"mergedTemplate", 0, &vOut, NULL, NULL))) { IWbemClassObject* pObj = NULL; if (SUCCEEDED(hr = vOut.punkVal->QueryInterface(IID_IWbemClassObject, (void**)&pObj))) { CReleaseMe relObj(pObj); hr = PrepResolveParam(pObj, pClassDef, pResolveParam); // place merged template into rsop/history object if (pRSOPNamespace) { VARIANT vObj; VariantInit(&vObj); vObj.vt = VT_UNKNOWN; vObj.punkVal = pObj; // no addref / no release / no clear pRsopTargetObj->Put(L"mergedTemplate", 0, &vObj, NULL); } if (pHistoryNamespace) { VARIANT vObj; VariantInit(&vObj); vObj.vt = VT_UNKNOWN; vObj.punkVal = pObj; // no addref / no release / no clear pHistoryTargetObj->Put(L"mergedTemplate", 0, &vObj, NULL); } // resolve merged template into object if (SUCCEEDED(hr = pPolicyNamespace->ExecMethod(bstrTemplate, bstrResolve, 0, NULL, pResolveParam, &pOut, NULL))) { if (SUCCEEDED(hr = pOut->Get(L"obj", 0, &vOut, NULL, NULL))) { IWbemClassObject* pTargetObj = NULL; if (SUCCEEDED(hr = vOut.punkVal->QueryInterface(IID_IWbemClassObject, (void**)&pTargetObj))) { CReleaseMe relTarget(pTargetObj); VARIANT vTargetPath; VariantInit(&vTargetPath); pTargetObj->Get(L"__RELPATH", 0, &vTargetPath, NULL, 0); if (pRsopTargetObj) { pRsopTargetObj->Put(L"TargetInstance", 0, &vOut, NULL); pRsopTargetObj->Put(L"TargetPath", 0, &vTargetPath, NULL); } if (pHistoryTargetObj) { pHistoryTargetObj->Put(L"TargetInstance", 0, &vOut, NULL); pHistoryTargetObj->Put(L"TargetPath", 0, &vTargetPath, NULL); } VariantClear(&vTargetPath); if (bDoItForReal && pTargetNamespace) { //hr = pTargetNamespace->PutInstance(pTargetObj, 0, NULL, NULL); hr = PutInstance(pTargetNamespace, pTargetObj); if (FAILED(hr)) ERRORTRACE((LOG_ESS, "CSE: PutInstance(pTargetObj) failed, 0x%08X\n", hr)); } } else hrOverall = hr; VariantClear(&vOut); } else hrOverall = hr; pOut->Release(); pOut = NULL; } else hrOverall = hr; VariantClear(&vOut); } else hrOverall = hr; } } else hrOverall = hr; if (pHistoryNamespace) pHistoryNamespace->PutInstance(pHistoryTargetObj, WBEM_FLAG_CREATE_OR_UPDATE, NULL, NULL); if (pRSOPNamespace) pRSOPNamespace->PutInstance(pRsopTargetObj, WBEM_FLAG_CREATE_OR_UPDATE, NULL, NULL); // clean up after yerself. pTargetNamespace->Release(); pTargetNamespace = NULL; SafeArrayDestroy(pList); pList = NULL; } if (pMergeParam) pMergeParam->Release(); if (pResolveParam) pResolveParam->Release(); return hrOverall; } DWORD WINAPI ProcessGroupPolicyAsync(LPVOID lpParameter) { HRESULT hr = WBEM_S_NO_ERROR; PGPStartup* pInfo = (PGPStartup*)lpParameter; #ifdef ASYNCH_ENABLED hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); if (FAILED(hr)) ERRORTRACE((LOG_ESS, "CSE: Coninit failed 0x%08X\n", hr)); else #endif { if (pInfo->pWbemServices) hr = EnsureRSOPSchema(pInfo->pWbemServices); else DEBUGTRACE((LOG_ESS, "CSE: No services pointer, cannot call ensure schema")); if (FAILED(hr)) { return hr; } // already done by caller. // if (FAILED(hr = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, 0))) // ERRORTRACE((LOG_ESS, "CSE: CoInitializeSecurity failed (0x%08X)\n", hr)); IWbemServices* pPolicyNamespace = NULL; if (SUCCEEDED(hr = GetPolicyNamespace(pPolicyNamespace))) { IWbemServices* pHistoryNamespace = NULL; if (SUCCEEDED(hr = GetHistoryNamespace(pHistoryNamespace))) { TemplateMap newPolicies; DeleteOldPolicies(pPolicyNamespace, pInfo->pWbemServices, pInfo->pDeletedGPOList, newPolicies); if (SUCCEEDED (hr = GetPolicyArray(pPolicyNamespace, pInfo->pChangedGPOList, pInfo->pWbemServices, pHistoryNamespace, newPolicies))) hr = ApplyPolicies(newPolicies, pPolicyNamespace, pInfo->pWbemServices, pHistoryNamespace, true); pHistoryNamespace->Release(); } pPolicyNamespace->Release(); } } #ifdef ASYNCH_ENABLED // NOTE: if this is re-enabled, pass the right hresult for RSOP ProcessGroupPolicyCompletedEx(&CLSID_CSE, pInfo->pHandle, HResultToWinError(hr), 0); #endif delete pInfo; #ifdef ASYNCH_ENABLED FreeLibraryAndExitThread(GetModuleHandleA("WMI_CSE.DLL"), 0); #endif return hr; } //*************************************************************************** // // Function: ProcessGroupPolicyEx // // Synopsis: DIAGNOSTIC MODE callback, // //*************************************************************************** DWORD ProcessGroupPolicyProcEx ( IN DWORD dwFlags, IN HANDLE hToken, IN HKEY hKeyRoot, IN PGROUP_POLICY_OBJECT pDeletedGPOList, IN PGROUP_POLICY_OBJECT pChangedGPOList, IN ASYNCCOMPLETIONHANDLE pHandle, IN BOOL *pbAbort, IN PFNSTATUSMESSAGECALLBACK pStatusCallback, IN IWbemServices *pWbemServices, OUT HRESULT *pRsopStatus) { DEBUGTRACE((LOG_ESS, "CSE: ProcessGroupPolicyProcEx\n")); #ifndef ASYNCH_ENABLED CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); #endif HRESULT hr = WBEM_S_NO_ERROR; PGPStartup* pInfo = new PGPStartup; if (pInfo) { pInfo->dwFlags = dwFlags; pInfo->hToken = hToken; pInfo->hKeyRoot = hKeyRoot; pInfo->pDeletedGPOList = pDeletedGPOList; pInfo->pChangedGPOList = pChangedGPOList; pInfo->pHandle = pHandle; pInfo->pbAbort = pbAbort; pInfo->pStatusCallback = pStatusCallback; pInfo->pWbemServices = pWbemServices; pInfo->pRsopStatus = pRsopStatus; DWORD threadIdAsIfICared; HANDLE threadHandleAsIfICared; #ifdef ASYNCH_ENABLED //okay, I gotta manage my own refcount to keep from being unloaded by WinLogon. LoadLibraryA("WMI_CSE.DLL"); threadHandleAsIfICared = CreateThread(NULL, 0, ProcessGroupPolicyAsync, (void*)pInfo, 0, &threadIdAsIfICared); if (threadHandleAsIfICared != NULL) { hr = WBEM_S_NO_ERROR; // debug hack to keep us from being unloaded too soon // WaitForSingleObject(threadHandleAsIfICared, INFINITE); CloseHandle(threadHandleAsIfICared); } else hr = WBEM_E_FAILED; #else hr = ProcessGroupPolicyAsync(pInfo); #endif } else hr = WBEM_E_OUT_OF_MEMORY; if FAILED(hr) ERRORTRACE((LOG_ESS, "CSE: ProcessGroupPolicyProcEx failed (0x%08X)\n", hr)); else DEBUGTRACE((LOG_ESS, "CSE: ProcessGroupPolicyProcEx Succeeded (0x%08X)\n", hr)); #ifdef ASYNCH_ENABLED if (hr == WBEM_S_NO_ERROR) return E_PENDING; else #endif return HResultToWinError(hr); } //*************************************************************************** // // Function: ProcessGroupPolicyProc // // Synopsis: callback, called by GPO when it's time to do policy stuff // //*************************************************************************** DWORD ProcessGroupPolicyProc( DWORD dwFlags, HANDLE hToken, HKEY hKeyRoot, PGROUP_POLICY_OBJECT pDeletedGPOList, PGROUP_POLICY_OBJECT pChangedGPOList, ASYNCCOMPLETIONHANDLE pHandle, BOOL *pbAbort, PFNSTATUSMESSAGECALLBACK pStatusCallback ) { DEBUGTRACE((LOG_ESS, "CSE: ProcessGroupPolicyProc\n")); return ProcessGroupPolicyProcEx(dwFlags, hToken, hKeyRoot, pDeletedGPOList, pChangedGPOList, pHandle, pbAbort, pStatusCallback, NULL, NULL); } //*************************************************************************** // // Function: GenerateGroupPolicy // // Synopsis: Planning Mode callback // //*************************************************************************** DWORD GenerateGroupPolicyProc ( IN DWORD dwFlags, IN BOOL *pbAbort, IN WCHAR *pwszSite, IN PRSOP_TARGET pComputerTarget, IN PRSOP_TARGET pUserTarget ) { DEBUGTRACE((LOG_ESS, "CSE: GenerateGroupPolicyProc\n")); HRESULT hr = WBEM_S_NO_ERROR; // no initialization needed // hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); if (FAILED(hr)) { ERRORTRACE((LOG_ESS, "CSE: Coninit failed 0x%08X\n", hr)); return E_FAIL; } else DEBUGTRACE((LOG_ESS, "CSE: Coninit returned 0x%08X\n", hr)); // already done by caller. if (FAILED(hr = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, 0))) ERRORTRACE((LOG_ESS, "CSE: CoInitializeSecurity failed (0x%08X)\n", hr)); IWbemServices* pPolicyNamespace = NULL; if (SUCCEEDED(hr = GetPolicyNamespace(pPolicyNamespace))) { TemplateMap policies; if (SUCCEEDED (hr = GetPolicyArray(pPolicyNamespace, pComputerTarget->pGPOList, pComputerTarget->pWbemServices, NULL, policies))) hr = ApplyPolicies(policies, pPolicyNamespace, pComputerTarget->pWbemServices, NULL, false); pPolicyNamespace->Release(); } if (FAILED(hr)) ERRORTRACE((LOG_ESS, "CSE: GenerateGroupPolicyProc failed (0x%08X)\n", hr)); else DEBUGTRACE((LOG_ESS, "CSE: GenerateGroupPolicyProc succeeded (0x%08X)\n", hr)); return HResultToWinError(hr); } //*************************************************************************** // // Function: LibMain // // Synopsis: Standard DLL initialization entrypoint // //*************************************************************************** extern "C" BOOL WINAPI LibMain(HINSTANCE hInst, ULONG ulReason, LPVOID pvReserved) { switch (ulReason) { case DLL_PROCESS_ATTACH: if (FAILED(CSEInitGlobalNames())) return FALSE; DisableThreadLibraryCalls(hInst); break; case DLL_PROCESS_DETACH: ReleaseGlobalNames(); break; default: break; } return TRUE; } //*************************************************************************** // // Function: DllMain // // Synopsis: entry point for NT - post .546 //*************************************************************************** extern "C" BOOL WINAPI DllMain(HANDLE hDll, DWORD dwReason, LPVOID lpReserved) { return LibMain((HINSTANCE)hDll, dwReason, lpReserved); } //*************************************************************************** // // DllRegisterServer // // Purpose: Called during setup or by regsvr32. // // Return: NOERROR if registration successful, error otherwise. //*************************************************************************** STDAPI DllRegisterServer(void) { HKEY hKey; LONG lResult; DWORD dwDisp; lResult = RegCreateKeyExA( HKEY_LOCAL_MACHINE, CSE_REG_KEY, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, &dwDisp); if (lResult == ERROR_SUCCESS) { // Get the dll's filename // ====================== char path[MAX_PATH +1]; GetModuleFileNameA(GetModuleHandleA("wmi_cse.dll"), path, MAX_PATH); unsigned char* ppath = (unsigned char*)&path[0]; RegSetValueExA( hKey, "DllName", 0, REG_EXPAND_SZ, ppath, lstrlenA(path) + 1 ); RegSetValueExA( hKey, "ProcessGroupPolicy", 0, REG_SZ, (unsigned char *)POLICY_PROC_NAME, lstrlenA(POLICY_PROC_NAME) + 1 ); RegSetValueExA( hKey, "ProcessGroupPolicyEx", 0, REG_SZ, (unsigned char *)POLICY_PROC_NAME_EX, lstrlenA(POLICY_PROC_NAME_EX) + 1 ); RegSetValueExA( hKey, "GenerateGroupPolicy", 0, REG_SZ, (unsigned char *)GENREATE_POLICY_PROC, lstrlenA(GENREATE_POLICY_PROC) + 1 ); RegSetValueExA( hKey, NULL, 0, REG_SZ, (unsigned char *)WMI_CSE_NAME, lstrlenA(WMI_CSE_NAME) + 1 ); DWORD trueVal = 1; DWORD falseVal = 0; #ifdef ASYNCH_ENABLED RegSetValueExA( hKey, "EnableAsynchronousProcessing", 0, REG_DWORD, (unsigned char *)&trueVal, sizeof(DWORD) ); else RegSetValueExA( hKey, "EnableAsynchronousProcessing", 0, REG_DWORD, (unsigned char *)&falseVal, sizeof(DWORD) ); #endif RegSetValueExA( hKey, "NoGPOListChanges", 0, REG_DWORD, (unsigned char *)&trueVal, sizeof(DWORD) ); RegCloseKey( hKey ); } else lResult = SELFREG_E_CLASS; return lResult; } //*************************************************************************** // // DllUnregisterServer // // Purpose: Called when it is time to remove the registry entries. // // Return: NOERROR if registration successful, error otherwise. //*************************************************************************** STDAPI DllUnregisterServer(void) { return SHDeleteKeyA(HKEY_LOCAL_MACHINE, CSE_REG_KEY); }