Leaked source code of windows server 2003
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.

648 lines
15 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. CWbemPtr<IUnknown> pNewCtx;
  246. if (bDoSwitchContext)
  247. {
  248. hr = pFilter->SetThreadSecurity( &pNewCtx );
  249. if(FAILED(hr))
  250. return hr;
  251. }
  252. CInCritSec ics(&m_cs);
  253. CUserInfo user;
  254. if (user.Init((LPBYTE) pSid, dwSize))
  255. {
  256. CUserMapIterator it;
  257. it= m_mapUserInfo.find(user);
  258. if (it!= m_mapUserInfo.end())
  259. {
  260. *pUser = new CUserMapIterator(it);
  261. if(*pUser == NULL)
  262. return WBEM_E_OUT_OF_MEMORY;
  263. return S_OK;
  264. }
  265. else
  266. {
  267. // Add it to the map.
  268. try
  269. {
  270. m_mapUserInfo[user] = 0;
  271. }
  272. catch(CX_MemoryException)
  273. {
  274. return WBEM_E_OUT_OF_MEMORY;
  275. }
  276. *pUser = new CUserMapIterator(m_mapUserInfo.find(user));
  277. if(*pUser == NULL)
  278. return WBEM_E_OUT_OF_MEMORY;
  279. return S_OK;
  280. }
  281. }
  282. else
  283. {
  284. // Special case for calls Winmgmt makes: doesn't count against any
  285. // user.
  286. *pUser = NULL;
  287. return S_FALSE;
  288. }
  289. }
  290. HRESULT CQuota::FreeUser(void* pUser)
  291. {
  292. delete (CUserMapIterator*)pUser;
  293. return S_OK;
  294. }
  295. HRESULT CQuota::IncrementQuotaIndex(
  296. ESS_QUOTA_INDEX dwIndex,
  297. CEventFilter *pFilter,
  298. DWORD dwToAdd)
  299. {
  300. HRESULT hr = S_OK;
  301. LPVOID pSid = NULL;
  302. DWORD dwSize;
  303. GetSidInfo(pFilter, &pSid, &dwSize);
  304. // We'll save the context if there's not a Sid.
  305. BOOL bDoSwitchContext = pSid == NULL;
  306. CSaveCallContext save(bDoSwitchContext);
  307. CWbemPtr<IUnknown> pNewCtx;
  308. if (bDoSwitchContext)
  309. {
  310. hr = pFilter->SetThreadSecurity( &pNewCtx );
  311. if(FAILED(hr))
  312. return hr;
  313. }
  314. Lock();
  315. if (m_dwGlobalCount[dwIndex] + dwToAdd <= m_dwGlobalLimits[dwIndex])
  316. {
  317. CUserInfo user;
  318. if (user.Init((LPBYTE) pSid, dwSize))
  319. {
  320. CUserMapIterator item;
  321. item = m_mapUserInfo.find(user);
  322. if (item != m_mapUserInfo.end())
  323. {
  324. CUserInfo &itemRef = (CUserInfo&) (*item).first;
  325. if (itemRef.m_dwUserCount[dwIndex] + dwToAdd <= m_dwUserLimits[dwIndex])
  326. {
  327. itemRef.m_dwUserCount[dwIndex] += dwToAdd;
  328. m_dwGlobalCount[dwIndex] += dwToAdd;
  329. }
  330. else
  331. hr = WBEM_E_QUOTA_VIOLATION;
  332. }
  333. else
  334. {
  335. // Set the number of items to dwToAdd.
  336. user.m_dwUserCount[dwIndex] = dwToAdd;
  337. // Add it to the map.
  338. try
  339. {
  340. m_mapUserInfo[user] = 0;
  341. }
  342. catch(CX_MemoryException)
  343. {
  344. hr = WBEM_E_OUT_OF_MEMORY;
  345. }
  346. if(SUCCEEDED(hr))
  347. {
  348. m_dwGlobalCount[dwIndex] += dwToAdd;
  349. }
  350. }
  351. }
  352. else
  353. {
  354. // Special case for calls Winmgmt makes: doesn't count against any
  355. // user.
  356. // Should this event count against our global counts?
  357. m_dwGlobalCount[dwIndex] += dwToAdd;
  358. }
  359. }
  360. else
  361. hr = WBEM_E_QUOTA_VIOLATION;
  362. Unlock();
  363. return hr;
  364. }
  365. HRESULT CQuota::DecrementQuotaIndex(
  366. ESS_QUOTA_INDEX dwIndex,
  367. CEventFilter *pFilter,
  368. DWORD dwToRemove)
  369. {
  370. CUserInfo user;
  371. BOOL bRet = FALSE;
  372. LPVOID pSid;
  373. DWORD dwSize;
  374. HRESULT hr;
  375. GetSidInfo(pFilter, &pSid, &dwSize);
  376. // We'll save the context if there's not a Sid.
  377. BOOL bDoSwitchContext = pSid == NULL;
  378. CSaveCallContext save(bDoSwitchContext);
  379. CWbemPtr<IUnknown> pNewCtx;
  380. if (bDoSwitchContext)
  381. {
  382. hr = pFilter->SetThreadSecurity( &pNewCtx );
  383. if(FAILED(hr))
  384. return hr;
  385. }
  386. Lock();
  387. m_dwGlobalCount[dwIndex] -= dwToRemove;
  388. if (user.Init((LPBYTE) pSid, dwSize))
  389. {
  390. CUserMapIterator item;
  391. item = m_mapUserInfo.find(user);
  392. if (item != m_mapUserInfo.end())
  393. {
  394. CUserInfo &itemRef = (CUserInfo&) (*item).first;
  395. itemRef.m_dwUserCount[dwIndex] -= dwToRemove;
  396. }
  397. }
  398. Unlock();
  399. return ERROR_SUCCESS;
  400. }
  401. HRESULT CQuota::IncrementQuotaIndexByUser(
  402. ESS_QUOTA_INDEX dwIndex,
  403. void *pUser,
  404. DWORD dwToAdd)
  405. {
  406. CUserMapIterator* pIt = (CUserMapIterator*)pUser;
  407. HRESULT hr = S_OK;
  408. Lock();
  409. if (m_dwGlobalCount[dwIndex] + dwToAdd <= m_dwGlobalLimits[dwIndex])
  410. {
  411. if(pIt)
  412. {
  413. CUserInfo &itemRef = (CUserInfo&) (*pIt)->first;
  414. if (itemRef.m_dwUserCount[dwIndex] + dwToAdd <=
  415. m_dwUserLimits[dwIndex])
  416. {
  417. itemRef.m_dwUserCount[dwIndex] += dwToAdd;
  418. m_dwGlobalCount[dwIndex] += dwToAdd;
  419. }
  420. else
  421. {
  422. hr = WBEM_E_QUOTA_VIOLATION;
  423. }
  424. }
  425. else
  426. {
  427. // Special case for calls Winmgmt makes: doesn't count against any
  428. // user.
  429. // Should this event count against our global counts?
  430. m_dwGlobalCount[dwIndex] += dwToAdd;
  431. }
  432. }
  433. else
  434. hr = WBEM_E_QUOTA_VIOLATION;
  435. Unlock();
  436. return hr;
  437. }
  438. HRESULT CQuota::DecrementQuotaIndexByUser(
  439. ESS_QUOTA_INDEX dwIndex,
  440. void *pUser,
  441. DWORD dwToRemove)
  442. {
  443. CUserMapIterator* pIt = (CUserMapIterator*)pUser;
  444. Lock();
  445. m_dwGlobalCount[dwIndex] -= dwToRemove;
  446. if (pIt)
  447. {
  448. CUserInfo &itemRef = (CUserInfo&) (*pIt)->first;
  449. _ASSERT(itemRef.m_dwUserCount[dwIndex] >= dwToRemove,
  450. L"Negative quotas!");
  451. itemRef.m_dwUserCount[dwIndex] -= dwToRemove;
  452. }
  453. Unlock();
  454. return S_OK;
  455. }
  456. const LPCWSTR szUserProps[] =
  457. {
  458. L"TemporarySubscriptionsPerUser",
  459. L"PermanentSubscriptionsPerUser",
  460. L"PollingInstructionsPerUser",
  461. L"PollingMemoryPerUser",
  462. };
  463. const LPCWSTR szGlobalProps[] =
  464. {
  465. L"TemporarySubscriptionsTotal",
  466. L"PermanentSubscriptionsTotal",
  467. L"PollingInstructionsTotal",
  468. L"PollingMemoryTotal",
  469. };
  470. void CQuota::UpdateQuotaSettings(IWbemClassObject *pObj)
  471. {
  472. VARIANT vTemp;
  473. VariantInit(&vTemp);
  474. Lock();
  475. for (int i = 0; i < ESSQ_INVALID_INDEX; i++)
  476. {
  477. if (SUCCEEDED(pObj->Get(szUserProps[i], 0, &vTemp, NULL, NULL)))
  478. m_dwUserLimits[i] = V_I4(&vTemp);
  479. if (SUCCEEDED(pObj->Get(szGlobalProps[i], 0, &vTemp, NULL, NULL)))
  480. m_dwGlobalLimits[i] = V_I4(&vTemp);
  481. }
  482. Unlock();
  483. }
  484. HRESULT WINAPI CQuota::Indicate(long lNumEvents, IWbemClassObject **ppEvents)
  485. {
  486. VARIANT vTemp;
  487. VariantInit(&vTemp);
  488. if (SUCCEEDED(ppEvents[lNumEvents - 1]->Get(
  489. L"TARGETINSTANCE", 0, &vTemp, NULL, NULL)))
  490. {
  491. IWbemClassObject *pObj = NULL;
  492. vTemp.punkVal->QueryInterface(IID_IWbemClassObject, (LPVOID*) &pObj);
  493. if (pObj)
  494. {
  495. UpdateQuotaSettings(pObj);
  496. pObj->Release();
  497. }
  498. }
  499. VariantClear(&vTemp);
  500. return S_OK;
  501. }
  502. CSaveCallContext::CSaveCallContext(BOOL bSave) :
  503. m_pSecurity(NULL)
  504. {
  505. m_bSaved = bSave;
  506. if (bSave)
  507. WbemCoGetCallContext(IID_IWbemCallSecurity, (LPVOID*) &m_pSecurity);
  508. }
  509. CSaveCallContext::~CSaveCallContext()
  510. {
  511. if (m_bSaved)
  512. {
  513. IUnknown *pPrev = NULL;
  514. CoSwitchCallContext(m_pSecurity, &pPrev);
  515. if (m_pSecurity)
  516. m_pSecurity->Release();
  517. }
  518. }