|
|
//=============================================================================
//
// Copyright (c) 2000, Microsoft Corporation, All rights reserved
//
// Quota.CPP
//
// Implements the class that keeps track of quotas within ESS.
//
//=============================================================================
#include "precomp.h"
#include <stdio.h>
#include "ess.h"
#include "essutils.h"
#include "nsrep.h"
#include "Quota.h"
#include <cominit.h>
#include <callsec.h>
// Global instance.
CQuota g_quotas;
#define WMICOREQUOTAS_NAMESPACE L"root"
#define WMICOREQUOTAS_OBJPATH L"__ArbitratorConfiguration=@"
#define WMICOREQUOTAS_CLASS L"__ArbitratorConfiguration"
CUserInfo::CUserInfo() : m_pData(NULL), m_dwSize(0), m_bAlloced(FALSE) { ZeroMemory(m_dwUserCount, sizeof(m_dwUserCount)); }
CUserInfo::CUserInfo(LPBYTE pData, DWORD dwSize) : m_pData(pData), m_dwSize(dwSize), m_bAlloced(FALSE) { ZeroMemory(m_dwUserCount, sizeof(m_dwUserCount)); }
CUserInfo::~CUserInfo() { if (m_pData && m_bAlloced) delete m_pData; }
BOOL CUserInfo::CopyData(LPBYTE pData, DWORD dwSize) { BOOL bRet;
m_pData = new BYTE[dwSize]; if (m_pData) { memcpy(m_pData, pData, dwSize); m_dwSize = dwSize; m_bAlloced = TRUE; bRet = TRUE; } else bRet = FALSE;
return bRet; }
const CUserInfo& CUserInfo::operator = (const CUserInfo& other) { if (other.m_bAlloced) { m_pData = other.m_pData; m_dwSize = other.m_dwSize; ((CUserInfo&)other).m_bAlloced = FALSE; m_bAlloced = TRUE; } else CopyData(other.m_pData, other.m_dwSize);
memcpy(m_dwUserCount, other.m_dwUserCount, sizeof(m_dwUserCount));
return *this; }
BOOL CUserInfo::Init(LPBYTE pData, DWORD dwSize) { BOOL bRet;
// See if we need to get the data out of the token.
if (!pData) { IWbemCallSecurity *pSecurity = NULL;
bRet = FALSE;
WbemCoGetCallContext(IID_IWbemCallSecurity, (void**) &pSecurity);
if (pSecurity) { // Get the client's SID.
TOKEN_USER tu; DWORD dwLen = 0; HANDLE hToken = pSecurity->GetToken(); GetTokenInformation( hToken, TokenUser, &tu, sizeof(tu), &dwLen);
if (dwLen != 0) { BYTE *pTemp = new BYTE[dwLen]; DWORD dwRealLen = dwLen;
if (pTemp) { if (GetTokenInformation( hToken, TokenUser, pTemp, dwRealLen, &dwLen)) { // Make a copy of the SID
PSID pSid = ((TOKEN_USER*)pTemp)->User.Sid; DWORD dwSidLen = GetLengthSid(pSid); m_pData = new BYTE[dwSidLen];
if (m_pData) { CopySid(dwSidLen, m_pData, pSid); m_dwSize = dwSidLen; m_bAlloced = TRUE;
bRet = TRUE; } }
delete [] pTemp; } }
pSecurity->Release(); } } else { m_pData = pData; m_dwSize = dwSize; m_bAlloced = FALSE;
bRet = TRUE; }
return bRet; }
#define DEF_GLOBAL_LIMIT 100
#define DEF_USER_LIMIT 20
CQuota::CQuota() : m_pEss(NULL) { // Zero this out.
ZeroMemory(m_dwGlobalCount, sizeof(m_dwGlobalCount)); // Setup some defaults. These will eventually get overridden once
// Init() is called.
for (int i = 0; i < ESSQ_INDEX_COUNT; i++) { m_dwGlobalLimits[i] = DEF_GLOBAL_LIMIT; m_dwUserLimits[i] = DEF_USER_LIMIT; }
m_dwGlobalLimits[ESSQ_POLLING_MEMORY] = 10000000; m_dwUserLimits[ESSQ_POLLING_MEMORY] = 5000000;
try { InitializeCriticalSection(&m_cs); } catch(...) { throw CX_MemoryException(); } }
HRESULT CQuota::Init(CEss *pEss) { HRESULT hr;
m_pEss = pEss;
CEssNamespace *pNamespace = NULL;
hr = pEss->GetNamespaceObject( WMICOREQUOTAS_NAMESPACE, TRUE, &pNamespace ); if (SUCCEEDED(hr)) { _IWmiObject *pObj = NULL;
hr = pNamespace->GetInstance( WMICOREQUOTAS_OBJPATH, &pObj);
if (SUCCEEDED(hr)) { UpdateQuotaSettings(pObj); pObj->Release();
{ CInUpdate iu( pNamespace );
hr = pNamespace->InternalRegisterNotificationSink( L"WQL", L"select * from __InstanceModificationEvent " L"where targetinstance isa '" WMICOREQUOTAS_CLASS L"'", 0, WMIMSG_FLAG_QOS_SYNCHRONOUS, GetCurrentEssContext(), this, true, NULL ); } pNamespace->FirePostponedOperations(); }
pNamespace->Release(); }
// Always return S_OK in case WMICOREQUOTAS_OBJPATH doesn't exist yet.
// Hopefully at some point this instance will always be there.
return S_OK; }
HRESULT CQuota::Shutdown() { if (m_pEss) m_pEss->RemoveNotificationSink(this); m_pEss = NULL; return S_OK; }
CQuota::~CQuota() { DeleteCriticalSection(&m_cs); }
bool CUserInfo::operator == (const CUserInfo& other) const { return m_dwSize == other.m_dwSize && !memcmp(m_pData, other.m_pData, m_dwSize); }
bool CUserInfo::operator < (const CUserInfo& other) const { if (m_dwSize < other.m_dwSize) return TRUE; else if (m_dwSize > other.m_dwSize) return FALSE; else return memcmp(m_pData, other.m_pData, m_dwSize) < 0; }
void GetSidInfo(CEventFilter *pFilter, LPVOID *ppSid, DWORD *pdwSize) { if (pFilter) { *ppSid = pFilter->GetOwner();
*pdwSize = *ppSid ? GetLengthSid(*ppSid) : 0; } else { *ppSid = NULL; *pdwSize = 0; } }
HRESULT CQuota::FindUser(CEventFilter* pFilter, void** pUser) { HRESULT hr = S_OK; LPVOID pSid = NULL; DWORD dwSize;
GetSidInfo(pFilter, &pSid, &dwSize);
// We'll save the context if there's not a Sid.
BOOL bDoSwitchContext = pSid == NULL; CSaveCallContext save(bDoSwitchContext); CWbemPtr<IUnknown> pNewCtx;
if (bDoSwitchContext) { hr = pFilter->SetThreadSecurity( &pNewCtx ); if(FAILED(hr)) return hr; }
CInCritSec ics(&m_cs); CUserInfo user; if (user.Init((LPBYTE) pSid, dwSize)) { CUserMapIterator it; it= m_mapUserInfo.find(user); if (it!= m_mapUserInfo.end()) { *pUser = new CUserMapIterator(it); if(*pUser == NULL) return WBEM_E_OUT_OF_MEMORY;
return S_OK; } else { // Add it to the map.
try { m_mapUserInfo[user] = 0; } catch(CX_MemoryException) { return WBEM_E_OUT_OF_MEMORY; }
*pUser = new CUserMapIterator(m_mapUserInfo.find(user)); if(*pUser == NULL) return WBEM_E_OUT_OF_MEMORY;
return S_OK; } } else { // Special case for calls Winmgmt makes: doesn't count against any
// user.
*pUser = NULL; return S_FALSE; } } HRESULT CQuota::FreeUser(void* pUser) { delete (CUserMapIterator*)pUser; return S_OK; }
HRESULT CQuota::IncrementQuotaIndex( ESS_QUOTA_INDEX dwIndex, CEventFilter *pFilter, DWORD dwToAdd) { HRESULT hr = S_OK; LPVOID pSid = NULL; DWORD dwSize;
GetSidInfo(pFilter, &pSid, &dwSize);
// We'll save the context if there's not a Sid.
BOOL bDoSwitchContext = pSid == NULL; CSaveCallContext save(bDoSwitchContext); CWbemPtr<IUnknown> pNewCtx;
if (bDoSwitchContext) { hr = pFilter->SetThreadSecurity( &pNewCtx ); if(FAILED(hr)) return hr; }
Lock(); if (m_dwGlobalCount[dwIndex] + dwToAdd <= m_dwGlobalLimits[dwIndex]) { CUserInfo user;
if (user.Init((LPBYTE) pSid, dwSize)) { CUserMapIterator item; item = m_mapUserInfo.find(user); if (item != m_mapUserInfo.end()) { CUserInfo &itemRef = (CUserInfo&) (*item).first;
if (itemRef.m_dwUserCount[dwIndex] + dwToAdd <= m_dwUserLimits[dwIndex]) { itemRef.m_dwUserCount[dwIndex] += dwToAdd; m_dwGlobalCount[dwIndex] += dwToAdd; } else hr = WBEM_E_QUOTA_VIOLATION; } else { // Set the number of items to dwToAdd.
user.m_dwUserCount[dwIndex] = dwToAdd;
// Add it to the map.
try { m_mapUserInfo[user] = 0; } catch(CX_MemoryException) { hr = WBEM_E_OUT_OF_MEMORY; }
if(SUCCEEDED(hr)) { m_dwGlobalCount[dwIndex] += dwToAdd; } } } else { // Special case for calls Winmgmt makes: doesn't count against any
// user.
// Should this event count against our global counts?
m_dwGlobalCount[dwIndex] += dwToAdd; } } else hr = WBEM_E_QUOTA_VIOLATION;
Unlock();
return hr; } HRESULT CQuota::DecrementQuotaIndex( ESS_QUOTA_INDEX dwIndex, CEventFilter *pFilter, DWORD dwToRemove) { CUserInfo user; BOOL bRet = FALSE; LPVOID pSid; DWORD dwSize; HRESULT hr;
GetSidInfo(pFilter, &pSid, &dwSize);
// We'll save the context if there's not a Sid.
BOOL bDoSwitchContext = pSid == NULL; CSaveCallContext save(bDoSwitchContext); CWbemPtr<IUnknown> pNewCtx;
if (bDoSwitchContext) { hr = pFilter->SetThreadSecurity( &pNewCtx ); if(FAILED(hr)) return hr; }
Lock(); m_dwGlobalCount[dwIndex] -= dwToRemove;
if (user.Init((LPBYTE) pSid, dwSize)) { CUserMapIterator item; item = m_mapUserInfo.find(user); if (item != m_mapUserInfo.end()) { CUserInfo &itemRef = (CUserInfo&) (*item).first;
itemRef.m_dwUserCount[dwIndex] -= dwToRemove; } }
Unlock(); return ERROR_SUCCESS; }
HRESULT CQuota::IncrementQuotaIndexByUser( ESS_QUOTA_INDEX dwIndex, void *pUser, DWORD dwToAdd) { CUserMapIterator* pIt = (CUserMapIterator*)pUser;
HRESULT hr = S_OK;
Lock(); if (m_dwGlobalCount[dwIndex] + dwToAdd <= m_dwGlobalLimits[dwIndex]) { if(pIt) { CUserInfo &itemRef = (CUserInfo&) (*pIt)->first; if (itemRef.m_dwUserCount[dwIndex] + dwToAdd <= m_dwUserLimits[dwIndex]) { itemRef.m_dwUserCount[dwIndex] += dwToAdd; m_dwGlobalCount[dwIndex] += dwToAdd; } else { hr = WBEM_E_QUOTA_VIOLATION; } } else { // Special case for calls Winmgmt makes: doesn't count against any
// user.
// Should this event count against our global counts?
m_dwGlobalCount[dwIndex] += dwToAdd; } } else hr = WBEM_E_QUOTA_VIOLATION;
Unlock();
return hr; } HRESULT CQuota::DecrementQuotaIndexByUser( ESS_QUOTA_INDEX dwIndex, void *pUser, DWORD dwToRemove) { CUserMapIterator* pIt = (CUserMapIterator*)pUser;
Lock(); m_dwGlobalCount[dwIndex] -= dwToRemove;
if (pIt) { CUserInfo &itemRef = (CUserInfo&) (*pIt)->first;
_ASSERT(itemRef.m_dwUserCount[dwIndex] >= dwToRemove, L"Negative quotas!");
itemRef.m_dwUserCount[dwIndex] -= dwToRemove; }
Unlock();
return S_OK; }
const LPCWSTR szUserProps[] = { L"TemporarySubscriptionsPerUser", L"PermanentSubscriptionsPerUser", L"PollingInstructionsPerUser", L"PollingMemoryPerUser", };
const LPCWSTR szGlobalProps[] = { L"TemporarySubscriptionsTotal", L"PermanentSubscriptionsTotal", L"PollingInstructionsTotal", L"PollingMemoryTotal", };
void CQuota::UpdateQuotaSettings(IWbemClassObject *pObj) { VARIANT vTemp;
VariantInit(&vTemp);
Lock();
for (int i = 0; i < ESSQ_INVALID_INDEX; i++) { if (SUCCEEDED(pObj->Get(szUserProps[i], 0, &vTemp, NULL, NULL))) m_dwUserLimits[i] = V_I4(&vTemp);
if (SUCCEEDED(pObj->Get(szGlobalProps[i], 0, &vTemp, NULL, NULL))) m_dwGlobalLimits[i] = V_I4(&vTemp); }
Unlock(); }
HRESULT WINAPI CQuota::Indicate(long lNumEvents, IWbemClassObject **ppEvents) { VARIANT vTemp;
VariantInit(&vTemp);
if (SUCCEEDED(ppEvents[lNumEvents - 1]->Get( L"TARGETINSTANCE", 0, &vTemp, NULL, NULL))) { IWbemClassObject *pObj = NULL; vTemp.punkVal->QueryInterface(IID_IWbemClassObject, (LPVOID*) &pObj);
if (pObj) { UpdateQuotaSettings(pObj);
pObj->Release(); } }
VariantClear(&vTemp);
return S_OK; }
CSaveCallContext::CSaveCallContext(BOOL bSave) : m_pSecurity(NULL) { m_bSaved = bSave;
if (bSave) WbemCoGetCallContext(IID_IWbemCallSecurity, (LPVOID*) &m_pSecurity); }
CSaveCallContext::~CSaveCallContext() { if (m_bSaved) { IUnknown *pPrev = NULL;
CoSwitchCallContext(m_pSecurity, &pPrev);
if (m_pSecurity) m_pSecurity->Release(); } }
|