Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

645 lines
14 KiB

  1. //=============================================================================
  2. //
  3. // Copyright (c) 2000, Microsoft Corporation, All rights reserved
  4. //
  5. // Quota.CPP
  6. //
  7. // Implements the class that keeps track of quotas within ESS.
  8. //
  9. //=============================================================================
  10. #include "precomp.h"
  11. #include <stdio.h>
  12. #include "ess.h"
  13. #include "essutils.h"
  14. #include "nsrep.h"
  15. #include "Quota.h"
  16. #include <cominit.h>
  17. #include <callsec.h>
  18. // Global instance.
  19. CQuota g_quotas;
  20. #define WMICOREQUOTAS_NAMESPACE L"root"
  21. #define WMICOREQUOTAS_OBJPATH L"__ArbitratorConfiguration=@"
  22. #define WMICOREQUOTAS_CLASS L"__ArbitratorConfiguration"
  23. CUserInfo::CUserInfo() :
  24. m_pData(NULL),
  25. m_dwSize(0),
  26. m_bAlloced(FALSE)
  27. {
  28. ZeroMemory(m_dwUserCount, sizeof(m_dwUserCount));
  29. }
  30. CUserInfo::CUserInfo(LPBYTE pData, DWORD dwSize) :
  31. m_pData(pData),
  32. m_dwSize(dwSize),
  33. m_bAlloced(FALSE)
  34. {
  35. ZeroMemory(m_dwUserCount, sizeof(m_dwUserCount));
  36. }
  37. CUserInfo::~CUserInfo()
  38. {
  39. if (m_pData && m_bAlloced)
  40. delete m_pData;
  41. }
  42. BOOL CUserInfo::CopyData(LPBYTE pData, DWORD dwSize)
  43. {
  44. BOOL bRet;
  45. m_pData = new BYTE[dwSize];
  46. if (m_pData)
  47. {
  48. memcpy(m_pData, pData, dwSize);
  49. m_dwSize = dwSize;
  50. m_bAlloced = TRUE;
  51. bRet = TRUE;
  52. }
  53. else
  54. bRet = FALSE;
  55. return bRet;
  56. }
  57. const CUserInfo& CUserInfo::operator = (const CUserInfo& other)
  58. {
  59. if (other.m_bAlloced)
  60. {
  61. m_pData = other.m_pData;
  62. m_dwSize = other.m_dwSize;
  63. ((CUserInfo&)other).m_bAlloced = FALSE;
  64. m_bAlloced = TRUE;
  65. }
  66. else
  67. CopyData(other.m_pData, other.m_dwSize);
  68. memcpy(m_dwUserCount, other.m_dwUserCount, sizeof(m_dwUserCount));
  69. return *this;
  70. }
  71. BOOL CUserInfo::Init(LPBYTE pData, DWORD dwSize)
  72. {
  73. BOOL bRet;
  74. // See if we need to get the data out of the token.
  75. if (!pData)
  76. {
  77. IWbemCallSecurity *pSecurity = NULL;
  78. bRet = FALSE;
  79. WbemCoGetCallContext(IID_IWbemCallSecurity, (void**) &pSecurity);
  80. if (pSecurity)
  81. {
  82. // Get the client's SID.
  83. TOKEN_USER tu;
  84. DWORD dwLen = 0;
  85. HANDLE hToken = pSecurity->GetToken();
  86. GetTokenInformation(
  87. hToken,
  88. TokenUser,
  89. &tu,
  90. sizeof(tu),
  91. &dwLen);
  92. if (dwLen != 0)
  93. {
  94. BYTE *pTemp = new BYTE[dwLen];
  95. DWORD dwRealLen = dwLen;
  96. if (pTemp)
  97. {
  98. if (GetTokenInformation(
  99. hToken,
  100. TokenUser,
  101. pTemp,
  102. dwRealLen,
  103. &dwLen))
  104. {
  105. // Make a copy of the SID
  106. PSID pSid = ((TOKEN_USER*)pTemp)->User.Sid;
  107. DWORD dwSidLen = GetLengthSid(pSid);
  108. m_pData = new BYTE[dwSidLen];
  109. if (m_pData)
  110. {
  111. CopySid(dwSidLen, m_pData, pSid);
  112. m_dwSize = dwSidLen;
  113. m_bAlloced = TRUE;
  114. bRet = TRUE;
  115. }
  116. }
  117. delete [] pTemp;
  118. }
  119. }
  120. pSecurity->Release();
  121. }
  122. }
  123. else
  124. {
  125. m_pData = pData;
  126. m_dwSize = dwSize;
  127. m_bAlloced = FALSE;
  128. bRet = TRUE;
  129. }
  130. return bRet;
  131. }
  132. #define DEF_GLOBAL_LIMIT 100
  133. #define DEF_USER_LIMIT 20
  134. CQuota::CQuota() :
  135. m_pEss(NULL)
  136. {
  137. // Zero this out.
  138. ZeroMemory(m_dwGlobalCount, sizeof(m_dwGlobalCount));
  139. // Setup some defaults. These will eventually get overridden once
  140. // Init() is called.
  141. for (int i = 0; i < ESSQ_INDEX_COUNT; i++)
  142. {
  143. m_dwGlobalLimits[i] = DEF_GLOBAL_LIMIT;
  144. m_dwUserLimits[i] = DEF_USER_LIMIT;
  145. }
  146. m_dwGlobalLimits[ESSQ_POLLING_MEMORY] = 10000000;
  147. m_dwUserLimits[ESSQ_POLLING_MEMORY] = 5000000;
  148. try
  149. {
  150. InitializeCriticalSection(&m_cs);
  151. }
  152. catch(...)
  153. {
  154. throw CX_MemoryException();
  155. }
  156. }
  157. HRESULT CQuota::Init(CEss *pEss)
  158. {
  159. HRESULT hr;
  160. m_pEss = pEss;
  161. CEssNamespace *pNamespace = NULL;
  162. hr =
  163. pEss->GetNamespaceObject(
  164. WMICOREQUOTAS_NAMESPACE,
  165. TRUE,
  166. &pNamespace );
  167. if (SUCCEEDED(hr))
  168. {
  169. _IWmiObject *pObj = NULL;
  170. hr =
  171. pNamespace->GetInstance(
  172. WMICOREQUOTAS_OBJPATH,
  173. &pObj);
  174. if (SUCCEEDED(hr))
  175. {
  176. UpdateQuotaSettings(pObj);
  177. pObj->Release();
  178. {
  179. CInUpdate iu( pNamespace );
  180. hr = pNamespace->InternalRegisterNotificationSink(
  181. L"WQL",
  182. L"select * from __InstanceModificationEvent "
  183. L"where targetinstance isa '" WMICOREQUOTAS_CLASS L"'",
  184. 0, WMIMSG_FLAG_QOS_SYNCHRONOUS,
  185. GetCurrentEssContext(),
  186. this,
  187. true,
  188. NULL );
  189. }
  190. pNamespace->FirePostponedOperations();
  191. }
  192. pNamespace->Release();
  193. }
  194. // Always return S_OK in case WMICOREQUOTAS_OBJPATH doesn't exist yet.
  195. // Hopefully at some point this instance will always be there.
  196. return S_OK;
  197. }
  198. HRESULT CQuota::Shutdown()
  199. {
  200. if (m_pEss)
  201. m_pEss->RemoveNotificationSink(this);
  202. m_pEss = NULL;
  203. return S_OK;
  204. }
  205. CQuota::~CQuota()
  206. {
  207. DeleteCriticalSection(&m_cs);
  208. }
  209. bool CUserInfo::operator == (const CUserInfo& other) const
  210. {
  211. return m_dwSize == other.m_dwSize &&
  212. !memcmp(m_pData, other.m_pData, m_dwSize);
  213. }
  214. bool CUserInfo::operator < (const CUserInfo& other) const
  215. {
  216. if (m_dwSize < other.m_dwSize)
  217. return TRUE;
  218. else if (m_dwSize > other.m_dwSize)
  219. return FALSE;
  220. else
  221. return memcmp(m_pData, other.m_pData, m_dwSize) < 0;
  222. }
  223. void GetSidInfo(CEventFilter *pFilter, LPVOID *ppSid, DWORD *pdwSize)
  224. {
  225. if (pFilter)
  226. {
  227. *ppSid = pFilter->GetOwner();
  228. *pdwSize = *ppSid ? GetLengthSid(*ppSid) : 0;
  229. }
  230. else
  231. {
  232. *ppSid = NULL;
  233. *pdwSize = 0;
  234. }
  235. }
  236. HRESULT CQuota::FindUser(CEventFilter* pFilter, void** pUser)
  237. {
  238. HRESULT hr = S_OK;
  239. LPVOID pSid = NULL;
  240. DWORD dwSize;
  241. GetSidInfo(pFilter, &pSid, &dwSize);
  242. // We'll save the context if there's not a Sid.
  243. BOOL bDoSwitchContext = pSid == NULL;
  244. CSaveCallContext save(bDoSwitchContext);
  245. if (bDoSwitchContext)
  246. {
  247. hr = pFilter->SetThreadSecurity();
  248. if(FAILED(hr))
  249. return hr;
  250. }
  251. CInCritSec ics(&m_cs);
  252. CUserInfo user;
  253. if (user.Init((LPBYTE) pSid, dwSize))
  254. {
  255. CUserMapIterator it;
  256. it= m_mapUserInfo.find(user);
  257. if (it!= m_mapUserInfo.end())
  258. {
  259. *pUser = new CUserMapIterator(it);
  260. if(*pUser == NULL)
  261. return WBEM_E_OUT_OF_MEMORY;
  262. return S_OK;
  263. }
  264. else
  265. {
  266. // Add it to the map.
  267. try
  268. {
  269. m_mapUserInfo[user] = 0;
  270. }
  271. catch(CX_MemoryException)
  272. {
  273. return WBEM_E_OUT_OF_MEMORY;
  274. }
  275. *pUser = new CUserMapIterator(m_mapUserInfo.find(user));
  276. if(*pUser == NULL)
  277. return WBEM_E_OUT_OF_MEMORY;
  278. return S_OK;
  279. }
  280. }
  281. else
  282. {
  283. // Special case for calls Winmgmt makes: doesn't count against any
  284. // user.
  285. *pUser = NULL;
  286. return S_FALSE;
  287. }
  288. }
  289. HRESULT CQuota::FreeUser(void* pUser)
  290. {
  291. delete (CUserMapIterator*)pUser;
  292. return S_OK;
  293. }
  294. HRESULT CQuota::IncrementQuotaIndex(
  295. ESS_QUOTA_INDEX dwIndex,
  296. CEventFilter *pFilter,
  297. DWORD dwToAdd)
  298. {
  299. HRESULT hr = S_OK;
  300. LPVOID pSid = NULL;
  301. DWORD dwSize;
  302. GetSidInfo(pFilter, &pSid, &dwSize);
  303. // We'll save the context if there's not a Sid.
  304. BOOL bDoSwitchContext = pSid == NULL;
  305. CSaveCallContext save(bDoSwitchContext);
  306. if (bDoSwitchContext)
  307. {
  308. hr = pFilter->SetThreadSecurity();
  309. if(FAILED(hr))
  310. return hr;
  311. }
  312. Lock();
  313. if (m_dwGlobalCount[dwIndex] + dwToAdd <= m_dwGlobalLimits[dwIndex])
  314. {
  315. CUserInfo user;
  316. if (user.Init((LPBYTE) pSid, dwSize))
  317. {
  318. CUserMapIterator item;
  319. item = m_mapUserInfo.find(user);
  320. if (item != m_mapUserInfo.end())
  321. {
  322. CUserInfo &itemRef = (CUserInfo&) (*item).first;
  323. if (itemRef.m_dwUserCount[dwIndex] + dwToAdd <= m_dwUserLimits[dwIndex])
  324. {
  325. itemRef.m_dwUserCount[dwIndex] += dwToAdd;
  326. m_dwGlobalCount[dwIndex] += dwToAdd;
  327. }
  328. else
  329. hr = WBEM_E_QUOTA_VIOLATION;
  330. }
  331. else
  332. {
  333. // Set the number of items to dwToAdd.
  334. user.m_dwUserCount[dwIndex] = dwToAdd;
  335. // Add it to the map.
  336. try
  337. {
  338. m_mapUserInfo[user] = 0;
  339. }
  340. catch(CX_MemoryException)
  341. {
  342. hr = WBEM_E_OUT_OF_MEMORY;
  343. }
  344. if(SUCCEEDED(hr))
  345. {
  346. m_dwGlobalCount[dwIndex] += dwToAdd;
  347. }
  348. }
  349. }
  350. else
  351. {
  352. // Special case for calls Winmgmt makes: doesn't count against any
  353. // user.
  354. // Should this event count against our global counts?
  355. m_dwGlobalCount[dwIndex] += dwToAdd;
  356. }
  357. }
  358. else
  359. hr = WBEM_E_QUOTA_VIOLATION;
  360. Unlock();
  361. return hr;
  362. }
  363. HRESULT CQuota::DecrementQuotaIndex(
  364. ESS_QUOTA_INDEX dwIndex,
  365. CEventFilter *pFilter,
  366. DWORD dwToRemove)
  367. {
  368. CUserInfo user;
  369. BOOL bRet = FALSE;
  370. LPVOID pSid;
  371. DWORD dwSize;
  372. HRESULT hr;
  373. GetSidInfo(pFilter, &pSid, &dwSize);
  374. // We'll save the context if there's not a Sid.
  375. BOOL bDoSwitchContext = pSid == NULL;
  376. CSaveCallContext save(bDoSwitchContext);
  377. if (bDoSwitchContext)
  378. {
  379. hr = pFilter->SetThreadSecurity();
  380. if(FAILED(hr))
  381. return hr;
  382. }
  383. Lock();
  384. m_dwGlobalCount[dwIndex] -= dwToRemove;
  385. if (user.Init((LPBYTE) pSid, dwSize))
  386. {
  387. CUserMapIterator item;
  388. item = m_mapUserInfo.find(user);
  389. if (item != m_mapUserInfo.end())
  390. {
  391. CUserInfo &itemRef = (CUserInfo&) (*item).first;
  392. itemRef.m_dwUserCount[dwIndex] -= dwToRemove;
  393. }
  394. }
  395. Unlock();
  396. return ERROR_SUCCESS;
  397. }
  398. HRESULT CQuota::IncrementQuotaIndexByUser(
  399. ESS_QUOTA_INDEX dwIndex,
  400. void *pUser,
  401. DWORD dwToAdd)
  402. {
  403. CUserMapIterator* pIt = (CUserMapIterator*)pUser;
  404. HRESULT hr = S_OK;
  405. Lock();
  406. if (m_dwGlobalCount[dwIndex] + dwToAdd <= m_dwGlobalLimits[dwIndex])
  407. {
  408. if(pIt)
  409. {
  410. CUserInfo &itemRef = (CUserInfo&) (*pIt)->first;
  411. if (itemRef.m_dwUserCount[dwIndex] + dwToAdd <=
  412. m_dwUserLimits[dwIndex])
  413. {
  414. itemRef.m_dwUserCount[dwIndex] += dwToAdd;
  415. m_dwGlobalCount[dwIndex] += dwToAdd;
  416. }
  417. else
  418. {
  419. hr = WBEM_E_QUOTA_VIOLATION;
  420. }
  421. }
  422. else
  423. {
  424. // Special case for calls Winmgmt makes: doesn't count against any
  425. // user.
  426. // Should this event count against our global counts?
  427. m_dwGlobalCount[dwIndex] += dwToAdd;
  428. }
  429. }
  430. else
  431. hr = WBEM_E_QUOTA_VIOLATION;
  432. Unlock();
  433. return hr;
  434. }
  435. HRESULT CQuota::DecrementQuotaIndexByUser(
  436. ESS_QUOTA_INDEX dwIndex,
  437. void *pUser,
  438. DWORD dwToRemove)
  439. {
  440. CUserMapIterator* pIt = (CUserMapIterator*)pUser;
  441. Lock();
  442. m_dwGlobalCount[dwIndex] -= dwToRemove;
  443. if (pIt)
  444. {
  445. CUserInfo &itemRef = (CUserInfo&) (*pIt)->first;
  446. _ASSERT(itemRef.m_dwUserCount[dwIndex] >= dwToRemove,
  447. L"Negative quotas!");
  448. itemRef.m_dwUserCount[dwIndex] -= dwToRemove;
  449. }
  450. Unlock();
  451. return S_OK;
  452. }
  453. const LPCWSTR szUserProps[] =
  454. {
  455. L"TemporarySubscriptionsPerUser",
  456. L"PermanentSubscriptionsPerUser",
  457. L"PollingInstructionsPerUser",
  458. L"PollingMemoryPerUser",
  459. };
  460. const LPCWSTR szGlobalProps[] =
  461. {
  462. L"TemporarySubscriptionsTotal",
  463. L"PermanentSubscriptionsTotal",
  464. L"PollingInstructionsTotal",
  465. L"PollingMemoryTotal",
  466. };
  467. void CQuota::UpdateQuotaSettings(IWbemClassObject *pObj)
  468. {
  469. VARIANT vTemp;
  470. VariantInit(&vTemp);
  471. Lock();
  472. for (int i = 0; i < ESSQ_INVALID_INDEX; i++)
  473. {
  474. if (SUCCEEDED(pObj->Get(szUserProps[i], 0, &vTemp, NULL, NULL)))
  475. m_dwUserLimits[i] = V_I4(&vTemp);
  476. if (SUCCEEDED(pObj->Get(szGlobalProps[i], 0, &vTemp, NULL, NULL)))
  477. m_dwGlobalLimits[i] = V_I4(&vTemp);
  478. }
  479. Unlock();
  480. }
  481. HRESULT WINAPI CQuota::Indicate(long lNumEvents, IWbemClassObject **ppEvents)
  482. {
  483. VARIANT vTemp;
  484. VariantInit(&vTemp);
  485. if (SUCCEEDED(ppEvents[lNumEvents - 1]->Get(
  486. L"TARGETINSTANCE", 0, &vTemp, NULL, NULL)))
  487. {
  488. IWbemClassObject *pObj = NULL;
  489. vTemp.punkVal->QueryInterface(IID_IWbemClassObject, (LPVOID*) &pObj);
  490. if (pObj)
  491. {
  492. UpdateQuotaSettings(pObj);
  493. pObj->Release();
  494. }
  495. }
  496. VariantClear(&vTemp);
  497. return S_OK;
  498. }
  499. CSaveCallContext::CSaveCallContext(BOOL bSave) :
  500. m_pSecurity(NULL)
  501. {
  502. m_bSaved = bSave;
  503. if (bSave)
  504. WbemCoGetCallContext(IID_IWbemCallSecurity, (LPVOID*) &m_pSecurity);
  505. }
  506. CSaveCallContext::~CSaveCallContext()
  507. {
  508. if (m_bSaved)
  509. {
  510. IUnknown *pPrev = NULL;
  511. CoSwitchCallContext(m_pSecurity, &pPrev);
  512. if (m_pSecurity)
  513. m_pSecurity->Release();
  514. }
  515. }