//============================================================================= // // Copyright (c) 1996-1999, Microsoft Corporation, All rights reserved // // PERMFILT.CPP // // This file implements the classes for standard event filters. // // History: // // 11/27/96 a-levn Compiles. // //============================================================================= #include "precomp.h" #include #include #include "pragmas.h" #include "permfilt.h" #include "ess.h" #include long CPermanentFilter::mstatic_lNameHandle = 0; long CPermanentFilter::mstatic_lLanguageHandle = 0; long CPermanentFilter::mstatic_lQueryHandle = 0; long CPermanentFilter::mstatic_lEventNamespaceHandle = 0; long CPermanentFilter::mstatic_lEventAccessHandle = 0; long CPermanentFilter::mstatic_lSidHandle = 0; bool CPermanentFilter::mstatic_bHandlesInitialized = false; //static HRESULT CPermanentFilter::InitializeHandles( _IWmiObject* pObject ) { if(mstatic_bHandlesInitialized) return S_FALSE; CIMTYPE ct; pObject->GetPropertyHandle(FILTER_KEY_PROPNAME, &ct, &mstatic_lNameHandle); pObject->GetPropertyHandle(FILTER_LANGUAGE_PROPNAME, &ct, &mstatic_lLanguageHandle); pObject->GetPropertyHandle(FILTER_QUERY_PROPNAME, &ct, &mstatic_lQueryHandle); pObject->GetPropertyHandle(FILTER_EVENTNAMESPACE_PROPNAME, &ct, &mstatic_lEventNamespaceHandle); pObject->GetPropertyHandleEx(FILTER_EVENTACCESS_PROPNAME, 0, &ct, &mstatic_lEventAccessHandle ); pObject->GetPropertyHandleEx(OWNER_SID_PROPNAME, 0, &ct, &mstatic_lSidHandle); mstatic_bHandlesInitialized = true; return S_OK; } //****************************************************************************** // public // // See stdtrig.h for documentation // //****************************************************************************** CPermanentFilter::CPermanentFilter(CEssNamespace* pNamespace) : CGenericFilter(pNamespace), m_pEventAccessRelativeSD(NULL), m_pcsQuery(NULL) { } CPermanentFilter::~CPermanentFilter() { if ( m_pEventAccessRelativeSD != NULL ) { LocalFree( m_pEventAccessRelativeSD ); } if( m_pcsQuery != NULL ) { CTemporaryHeap::Free(m_pcsQuery, m_pcsQuery->GetLength()); } } HRESULT CPermanentFilter::Initialize( IWbemClassObject* pObj ) { HRESULT hres; CWbemPtr<_IWmiObject> pFilterObj; hres = pObj->QueryInterface( IID__IWmiObject, (void**)&pFilterObj ); if ( FAILED(hres) ) { return hres; } InitializeHandles( pFilterObj ); // Check class // =========== if(pFilterObj->InheritsFrom(L"__EventFilter") != S_OK) return WBEM_E_INVALID_OBJECT; // Determine the query language // ============================ ULONG ulFlags; CCompressedString* pcsLanguage; hres = pFilterObj->GetPropAddrByHandle( mstatic_lLanguageHandle, WMIOBJECT_FLAG_ENCODING_V1, &ulFlags, (void**)&pcsLanguage ); if( hres != S_OK || pcsLanguage == NULL) { ERRORTRACE((LOG_ESS, "Event filter with invalid query language is " "rejected\n")); return WBEM_E_INVALID_OBJECT; } if( pcsLanguage->CompareNoCase("WQL") != 0 ) { ERRORTRACE((LOG_ESS, "Event filter with invalid query language '%S' is " "rejected\n", pcsLanguage->CreateWStringCopy())); return WBEM_E_INVALID_QUERY_TYPE; } // Get the query // ============= CCompressedString* pcsQuery; hres = pFilterObj->GetPropAddrByHandle( mstatic_lQueryHandle, WMIOBJECT_FLAG_ENCODING_V1, &ulFlags, (void**)&pcsQuery ); if( hres != S_OK ) { return WBEM_E_INVALID_OBJECT; } LPWSTR wszQuery = pcsQuery->CreateWStringCopy().UnbindPtr(); if(wszQuery == NULL) return WBEM_E_OUT_OF_MEMORY; CVectorDeleteMe vdm1(wszQuery); // Store it temporarily (until Park is called) // =========================================== // Figure out how much space we need // ================================= int nSpace = pcsQuery->GetLength(); // Allocate this string on the temporary heap // ========================================== m_pcsQuery = (CCompressedString*)CTemporaryHeap::Alloc(nSpace); if(m_pcsQuery == NULL) return WBEM_E_OUT_OF_MEMORY; // Copy the contents // ================= memcpy((void*)m_pcsQuery, pcsQuery, nSpace); // // Get the event namespace // if(mstatic_lEventNamespaceHandle) // to protect against old repositories { CCompressedString* pcsEventNamespace; hres = pFilterObj->GetPropAddrByHandle( mstatic_lEventNamespaceHandle, WMIOBJECT_FLAG_ENCODING_V1, &ulFlags, (void**)&pcsEventNamespace ); if( FAILED(hres) ) { return hres; } else if ( hres == S_OK ) // o.k if event namespace is null. { if( !(m_isEventNamespace = pcsEventNamespace)) { return WBEM_E_OUT_OF_MEMORY; } } } // // Record the name of this filter // CCompressedString* pcsKey; hres = pFilterObj->GetPropAddrByHandle( mstatic_lNameHandle, WMIOBJECT_FLAG_ENCODING_V1, &ulFlags, (void**)&pcsKey ); if( hres != S_OK ) { return WBEM_E_INVALID_OBJECT; } if(!(m_isKey = pcsKey)) return WBEM_E_OUT_OF_MEMORY; // Get the SID // =========== PSID pSid; ULONG ulNumElements; hres = pFilterObj->GetArrayPropAddrByHandle( mstatic_lSidHandle, 0, &ulNumElements, &pSid ); if ( hres != S_OK ) { return WBEM_E_INVALID_OBJECT; } m_pOwnerSid = new BYTE[ulNumElements]; if ( m_pOwnerSid == NULL ) { return WBEM_E_OUT_OF_MEMORY; } memcpy( m_pOwnerSid, pSid, ulNumElements ); // // Get the event access SD // if( mstatic_lEventAccessHandle ) // to protect against old repositories { CCompressedString* pcsEventAccess; hres = pFilterObj->GetPropAddrByHandle( mstatic_lEventAccessHandle, WMIOBJECT_FLAG_ENCODING_V1, &ulFlags, (void**)&pcsEventAccess ); if( FAILED(hres) ) { return hres; } else if ( hres == S_OK ) // o.k if event access is null. { WString wsEventAccess; try { wsEventAccess = pcsEventAccess->CreateWStringCopy(); } catch( CX_MemoryException ) { return WBEM_E_OUT_OF_MEMORY; } ULONG cEventAccessRelativeSD; if ( !ConvertStringSecurityDescriptorToSecurityDescriptorW( wsEventAccess, SDDL_REVISION_1, &m_pEventAccessRelativeSD, &cEventAccessRelativeSD ) ) { WString wsKey = m_isKey; try { wsKey = m_isKey; } catch( CX_MemoryException ) {} ERRORTRACE((LOG_ESS, "Filter '%S' contained invalid SDDL " "string for event access SD.\n", wsKey )); return HRESULT_FROM_WIN32( GetLastError() ); } // // convert the self-relative SD to an absolute SD so we can // set the owner and group fields ( required by AccessCheck ) // if ( !InitializeSecurityDescriptor( &m_EventAccessAbsoluteSD, SECURITY_DESCRIPTOR_REVISION )) { return HRESULT_FROM_WIN32( GetLastError() ); } PACL pAcl; BOOL bAclPresent, bAclDefaulted; if ( !GetSecurityDescriptorDacl( m_pEventAccessRelativeSD, &bAclPresent, &pAcl, &bAclDefaulted ) ) { return HRESULT_FROM_WIN32( GetLastError() ); } if ( !SetSecurityDescriptorDacl( &m_EventAccessAbsoluteSD, bAclPresent, pAcl, bAclDefaulted ) ) { return HRESULT_FROM_WIN32( GetLastError() ); } if ( !GetSecurityDescriptorSacl( m_pEventAccessRelativeSD, &bAclPresent, &pAcl, &bAclDefaulted ) ) { return HRESULT_FROM_WIN32( GetLastError() ); } if ( !SetSecurityDescriptorSacl( &m_EventAccessAbsoluteSD, bAclPresent, pAcl, bAclDefaulted ) ) { return HRESULT_FROM_WIN32( GetLastError() ); } // // always need to set the owner and group sids. We do this for // two reasons (1) we want to override the user putting in anything // they want for these fields, and (2) we want to ensure that // these fields are set because AccessCheck() requires it. // if ( !SetSecurityDescriptorOwner( &m_EventAccessAbsoluteSD, m_pOwnerSid, TRUE ) ) { return HRESULT_FROM_WIN32( GetLastError() ); } if ( !SetSecurityDescriptorGroup( &m_EventAccessAbsoluteSD, m_pOwnerSid, TRUE ) ) { return HRESULT_FROM_WIN32( GetLastError() ); } } } // Initialize the generic filter accordingly // ========================================= hres = CGenericFilter::Create(L"WQL", wszQuery); if(FAILED(hres)) return hres; return WBEM_S_NO_ERROR; } const PSECURITY_DESCRIPTOR CPermanentFilter::GetEventAccessSD() { if ( m_pEventAccessRelativeSD != NULL ) { return &m_EventAccessAbsoluteSD; } return NULL; } HRESULT CPermanentFilter::GetCoveringQuery(DELETE_ME LPWSTR& wszQueryLanguage, DELETE_ME LPWSTR& wszQuery, BOOL& bExact, QL_LEVEL_1_RPN_EXPRESSION** ppExp) { HRESULT hres; if(m_pcsQuery == NULL) { hres = RetrieveQuery(wszQuery); } else { wszQuery = m_pcsQuery->CreateWStringCopy().UnbindPtr(); if(wszQuery == NULL) hres = WBEM_E_OUT_OF_MEMORY; else hres = WBEM_S_NO_ERROR; } if(FAILED(hres)) return hres; if(ppExp) { // Parse it // ======== CTextLexSource src(wszQuery); QL1_Parser parser(&src); int nRes = parser.Parse(ppExp); if (nRes) { ERRORTRACE((LOG_ESS, "Unable to construct event filter with " "unparsable " "query '%S'. The filter is not active\n", wszQuery)); return WBEM_E_UNPARSABLE_QUERY; } } bExact = TRUE; wszQueryLanguage = CloneWstr(L"WQL"); return WBEM_S_NO_ERROR; } HRESULT CPermanentFilter::RetrieveQuery(DELETE_ME LPWSTR& wszQuery) { HRESULT hres; // // Construct db path // DWORD cLen = m_isKey.GetLength() + 100; BSTR strPath = SysAllocStringLen(NULL, cLen ); if(strPath == NULL) return WBEM_E_OUT_OF_MEMORY; CSysFreeMe sfm1(strPath); StringCchPrintfW( strPath, cLen, L"__EventFilter=\"%s\"", (LPCWSTR)(WString)m_isKey ); // // Retrieve the object // _IWmiObject* pFilterObj; hres = m_pNamespace->GetDbInstance(strPath, &pFilterObj); if(FAILED(hres)) return WBEM_E_INVALID_OBJECT; CReleaseMe rm(pFilterObj); InitializeHandles(pFilterObj); // Extract its properties // ====================== ULONG ulFlags; CCompressedString* pcsQuery; hres = pFilterObj->GetPropAddrByHandle( mstatic_lQueryHandle, WMIOBJECT_FLAG_ENCODING_V1, &ulFlags, (void**)&pcsQuery ); if( hres != S_OK ) { return WBEM_E_INVALID_OBJECT; } wszQuery = pcsQuery->CreateWStringCopy().UnbindPtr(); if(wszQuery == NULL) return WBEM_E_OUT_OF_MEMORY; return WBEM_S_NO_ERROR; } HRESULT CPermanentFilter::GetEventNamespace( DELETE_ME LPWSTR* pwszNamespace) { if(m_isEventNamespace.IsEmpty()) *pwszNamespace = NULL; else { *pwszNamespace = m_isEventNamespace.CreateLPWSTRCopy(); if(*pwszNamespace == NULL) return WBEM_E_OUT_OF_MEMORY; } return S_OK; } SYSFREE_ME BSTR CPermanentFilter::ComputeKeyFromObj( IWbemClassObject* pObj ) { HRESULT hres; CWbemPtr<_IWmiObject> pFilterObj; hres = pObj->QueryInterface( IID__IWmiObject, (void**)&pFilterObj ); if ( FAILED(hres) ) { return NULL; } InitializeHandles(pFilterObj); ULONG ulFlags; CCompressedString* pcsKey; hres = pFilterObj->GetPropAddrByHandle( mstatic_lNameHandle, WMIOBJECT_FLAG_ENCODING_V1, &ulFlags, (void**)&pcsKey ); if( hres != S_OK ) { return NULL; } return pcsKey->CreateBSTRCopy(); } SYSFREE_ME BSTR CPermanentFilter::ComputeKeyFromPath( LPCWSTR wszPath) { // Find the first quote // ==================== WCHAR* pwcFirstQuote = wcschr(wszPath, L'"'); if(pwcFirstQuote == NULL) return NULL; // Find the next quote // =================== WCHAR* pwcLastQuote = wcschr(pwcFirstQuote+1, L'"'); if(pwcLastQuote == NULL) return NULL; return SysAllocStringLen(pwcFirstQuote+1, pwcLastQuote - pwcFirstQuote - 1); } HRESULT CPermanentFilter::CheckValidity( IWbemClassObject* pObj ) { HRESULT hres; CWbemPtr<_IWmiObject> pFilterObj; hres = pObj->QueryInterface( IID__IWmiObject, (void**)&pFilterObj ); if ( FAILED(hres) ) { return hres; } InitializeHandles(pFilterObj); // // Check class // if(pFilterObj->InheritsFrom(L"__EventFilter") != S_OK) return WBEM_E_INVALID_OBJECT; // // Check the query language // ULONG ulFlags; CCompressedString* pcsLanguage; hres = pFilterObj->GetPropAddrByHandle( mstatic_lLanguageHandle, WMIOBJECT_FLAG_ENCODING_V1, &ulFlags, (void**)&pcsLanguage ); if( hres != S_OK ) { return WBEM_E_INVALID_QUERY_TYPE; } if(pcsLanguage->CompareNoCase("WQL") != 0) return WBEM_E_INVALID_QUERY_TYPE; // // Get the query // CCompressedString* pcsQuery; hres = pFilterObj->GetPropAddrByHandle( mstatic_lQueryHandle, WMIOBJECT_FLAG_ENCODING_V1, &ulFlags, (void**)&pcsQuery ); if( hres != S_OK ) { return WBEM_E_INVALID_OBJECT; } LPWSTR wszQuery = pcsQuery->CreateWStringCopy().UnbindPtr(); if(wszQuery == NULL) return WBEM_E_OUT_OF_MEMORY; CVectorDeleteMe vdm(wszQuery); // // Make sure it is parsable // CTextLexSource src(wszQuery); QL1_Parser parser(&src); QL_LEVEL_1_RPN_EXPRESSION* pExp = NULL; int nRes = parser.Parse(&pExp); if (nRes) return WBEM_E_UNPARSABLE_QUERY; delete pExp; return WBEM_S_NO_ERROR; } HRESULT CPermanentFilter::ObtainToken(IWbemToken** ppToken) { // // Get us a token from the token cache // return m_pNamespace->GetToken(GetOwner(), ppToken); } void CPermanentFilter::Park() { if(m_pcsQuery) CTemporaryHeap::Free(m_pcsQuery, m_pcsQuery->GetLength()); m_pcsQuery = NULL; }