windows-nt/Source/XPSP1/NT/admin/wmi/wbem/winmgmt/ess3/permfilt.cpp
2020-09-26 16:20:57 +08:00

682 lines
20 KiB
C++

//=============================================================================
//
// 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 <sddl.h>
#include <stdio.h>
#include "pragmas.h"
#include "permfilt.h"
#include "ess.h"
#include <genutils.h>
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_lGuardNamespaceHandle = 0;
long CPermanentFilter::mstatic_lGuardHandle = 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->GetPropertyHandle(FILTER_GUARDNAMESPACE_PROPNAME, &ct,
&mstatic_lGuardNamespaceHandle);
pObject->GetPropertyHandle(FILTER_GUARD_PROPNAME, &ct,
&mstatic_lGuardHandle);
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)
{
}
CPermanentFilter::~CPermanentFilter()
{
if ( m_pEventAccessRelativeSD != NULL )
{
LocalFree( m_pEventAccessRelativeSD );
}
}
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<WCHAR> 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;
}
}
}
CCompressedString* pcsGuard = NULL;
if(mstatic_lGuardHandle) // to protect against old repositories
{
hres = pFilterObj->GetPropAddrByHandle( mstatic_lGuardHandle,
WMIOBJECT_FLAG_ENCODING_V1,
&ulFlags,
(void**)&pcsGuard );
if( FAILED(hres) )
return hres;
}
if(pcsGuard)
{
CCompressedString* pcsGuardNamespace = NULL;
if(mstatic_lGuardNamespaceHandle) // to protect against old repositories
{
hres = pFilterObj->GetPropAddrByHandle(
mstatic_lGuardNamespaceHandle,
WMIOBJECT_FLAG_ENCODING_V1,
&ulFlags,
(void**)&pcsGuardNamespace );
if( FAILED(hres) )
return hres;
}
//
// Check query type
//
VARIANT vType;
VariantInit(&vType);
CClearMe cm1(&vType);
hres = pFilterObj->Get(FILTER_GUARDLANG_PROPNAME, 0, &vType, NULL,
NULL);
if(FAILED(hres))
{
ERRORTRACE((LOG_ESS, "Condition without a query type? Not valid\n"));
return hres;
}
if(V_VT(&vType) != VT_BSTR)
{
ERRORTRACE((LOG_ESS, "Condition without a query type? Not "
"valid\n"));
return WBEM_E_INVALID_OBJECT;
}
if(wbem_wcsicmp(V_BSTR(&vType), L"WQL"))
{
ERRORTRACE((LOG_ESS, "Condition with invalid query type %S is "
"rejected\n", V_BSTR(&vType)));
return hres;
}
if(pcsGuardNamespace)
hres = SetGuardQuery(pcsGuard->CreateWStringCopy(),
pcsGuardNamespace->CreateWStringCopy());
else
hres = SetGuardQuery(pcsGuard->CreateWStringCopy(), NULL);
if( FAILED(hres) )
return hres;
}
//
// 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
//
BSTR strPath = SysAllocStringLen(NULL, m_isKey.GetLength() + 100);
if(strPath == NULL)
return WBEM_E_OUT_OF_MEMORY;
CSysFreeMe sfm1(strPath);
swprintf(strPath, 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<WCHAR> 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;
}