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.

953 lines
24 KiB

  1. /*++
  2. Copyright (C) 1996-2001 Microsoft Corporation
  3. Module Name:
  4. REGEPROV.CPP
  5. Abstract:
  6. History:
  7. --*/
  8. #include "precomp.h"
  9. #include <wbemidl.h>
  10. #include <stdio.h>
  11. #include "cfdyn.h"
  12. #include "stdprov.h"
  13. #include "regeprov.h"
  14. #include <sync.h>
  15. #include <tss.h>
  16. #include <genutils.h>
  17. #include <analyser.h>
  18. #include <cominit.h>
  19. #include <GroupsForUser.h>
  20. template <class T>
  21. class CLockUnlock
  22. {
  23. private:
  24. T *m_pObj;
  25. public:
  26. CLockUnlock(T *pObj) : m_pObj(pObj) { if(pObj) pObj->Lock(); }
  27. ~CLockUnlock() { if(m_pObj) m_pObj->Unlock(); }
  28. };
  29. CRegEventProvider::CRegEventProvider()
  30. : m_lRef(0), m_hThread(NULL), m_dwId(NULL),
  31. m_pKeyClass(NULL), m_pValueClass(NULL), m_pTreeClass(NULL), m_pSink(NULL)
  32. {
  33. InitializeCriticalSection(&m_cs);
  34. InitializeCriticalSection(&m_csQueueLock);
  35. m_hQueueSemaphore = CreateSemaphore(NULL, // lpSemaphoreAttributes
  36. 0, // lInitialCount
  37. 0x7fffffff, // lMaximumCount
  38. NULL); // lpName
  39. }
  40. CRegEventProvider::~CRegEventProvider()
  41. {
  42. if(m_pSink)
  43. m_pSink->Release();
  44. if(m_pKeyClass)
  45. m_pKeyClass->Release();
  46. if(m_pValueClass)
  47. m_pValueClass->Release();
  48. if(m_pTreeClass)
  49. m_pTreeClass->Release();
  50. DeleteCriticalSection(&m_cs);
  51. DeleteCriticalSection(&m_csQueueLock);
  52. InterlockedDecrement(&lObj);
  53. if (m_hThread) CloseHandle(m_hThread);
  54. if (m_hQueueSemaphore) CloseHandle(m_hQueueSemaphore);
  55. }
  56. STDMETHODIMP CRegEventProvider::QueryInterface(REFIID riid, void** ppv)
  57. {
  58. if(riid == IID_IWbemEventProvider || riid == IID_IUnknown)
  59. {
  60. *ppv = (IWbemEventProvider*)this;
  61. AddRef();
  62. return S_OK;
  63. }
  64. else if(riid == IID_IWbemEventProviderQuerySink)
  65. {
  66. *ppv = (IWbemEventProviderQuerySink*)this;
  67. AddRef();
  68. return S_OK;
  69. }
  70. else if(riid == IID_IWbemEventProviderSecurity)
  71. {
  72. *ppv = (IWbemEventProviderSecurity*)this;
  73. AddRef();
  74. return S_OK;
  75. }
  76. else if(riid == IID_IWbemProviderInit)
  77. {
  78. *ppv = (IWbemProviderInit*)this;
  79. AddRef();
  80. return S_OK;
  81. }
  82. else return E_NOINTERFACE;
  83. }
  84. ULONG STDMETHODCALLTYPE CRegEventProvider::AddRef()
  85. {
  86. return InterlockedIncrement(&m_lRef);
  87. }
  88. ULONG STDMETHODCALLTYPE CRegEventProvider::Release()
  89. {
  90. long lRef = InterlockedDecrement(&m_lRef);
  91. if(lRef == 0)
  92. {
  93. {
  94. CInCritSec ics(&m_cs);
  95. // deactivate all event requests
  96. for(int i = 0; i < m_apRequests.GetSize(); i++)
  97. {
  98. CRegistryEventRequest* pReq = m_apRequests[i];
  99. if(pReq) pReq->ForceDeactivate();
  100. }
  101. m_apRequests.RemoveAll();
  102. if(m_hThread) KillWorker();
  103. }
  104. /* *m_pbEnd = TRUE;
  105. m_lRef = 1;
  106. HANDLE hThread = m_hThread;
  107. CycleWorker();
  108. WaitForSingleObject(hThread, 5000);
  109. */
  110. delete this;
  111. }
  112. return lRef;
  113. }
  114. STDMETHODIMP CRegEventProvider::Initialize(LPWSTR wszUser,
  115. long lFlags,
  116. LPWSTR wszNamespace,
  117. LPWSTR wszLocale,
  118. IWbemServices* pNamespace,
  119. IWbemContext* pCtx,
  120. IWbemProviderInitSink* pSink)
  121. {
  122. HRESULT hres = pNamespace->GetObject(REG_KEY_EVENT_CLASS,// strObjectPath
  123. 0, // lFlags
  124. pCtx, // pCtx
  125. &m_pKeyClass, // ppObject
  126. NULL); // ppCallResult
  127. hres = pNamespace->GetObject(REG_VALUE_EVENT_CLASS,
  128. 0,
  129. pCtx,
  130. &m_pValueClass,
  131. NULL);
  132. hres = pNamespace->GetObject(REG_TREE_EVENT_CLASS,
  133. 0,
  134. pCtx,
  135. &m_pTreeClass,
  136. NULL);
  137. pSink->SetStatus(hres, 0);
  138. return hres;
  139. }
  140. STDMETHODIMP CRegEventProvider::ProvideEvents(IWbemObjectSink* pSink,
  141. long lFlags)
  142. {
  143. m_pSink = pSink;
  144. pSink->AddRef();
  145. return S_OK;
  146. }
  147. HRESULT CRegEventProvider::AddRequest(CRegistryEventRequest* pNewReq)
  148. {
  149. // This is only called after entering the critical section m_cs
  150. int nActiveRequests = m_apRequests.GetSize();
  151. // Search for a similar request
  152. // ============================
  153. // This will not change the number of active requests.
  154. // It will cause the request Id to be served by an existing
  155. // CRegistryEventRequest.
  156. for(int i = 0; i < nActiveRequests; i++)
  157. {
  158. CRegistryEventRequest* pReq = m_apRequests[i];
  159. // Only active requests are in the array.
  160. if(pReq->IsSameAs(pNewReq))
  161. {
  162. // Found it!
  163. // =========
  164. HRESULT hres = pReq->Reactivate(pNewReq->GetPrimaryId(),
  165. pNewReq->GetMsWait());
  166. delete pNewReq;
  167. return hres;
  168. }
  169. }
  170. // Not found. Add it
  171. // =================
  172. HRESULT hres = pNewReq->Activate();
  173. if(SUCCEEDED(hres))
  174. {
  175. m_apRequests.Add(pNewReq);
  176. // If there were no active requests before this one was added
  177. // then we have to start up the worker thread.
  178. if ( nActiveRequests == 0 )
  179. {
  180. CreateWorker();
  181. }
  182. }
  183. return hres;
  184. }
  185. STDMETHODIMP CRegEventProvider::CancelQuery(DWORD dwId)
  186. {
  187. CInCritSec ics(&m_cs);
  188. int nOriginalSize = m_apRequests.GetSize();
  189. // Remove all requests with this Id
  190. // ================================
  191. for(int i = 0; i < m_apRequests.GetSize(); i++)
  192. {
  193. CRegistryEventRequest* pReq = m_apRequests[i];
  194. // If Deactivate returns WBEM_S_FALSE then the request was not serving
  195. // this id or it is still serving other ids so we leave it in the array.
  196. // If S_OK is returned then the request is no longer serving any ids
  197. // and it is marked as inactive and its resources are released. There
  198. // may still be references to it in the worker thread queue, but the
  199. // worker thread will see that it is inactive and not fire the events.
  200. if (pReq->Deactivate(dwId) == S_OK)
  201. {
  202. m_apRequests.RemoveAt(i);
  203. --i;
  204. }
  205. }
  206. // If we have cancelled the last subscription then kill the worker thread.
  207. if (nOriginalSize > 0 && m_apRequests.GetSize() == 0)
  208. {
  209. if(m_hThread) KillWorker();
  210. }
  211. return WBEM_S_NO_ERROR;
  212. }
  213. void CRegEventProvider::CreateWorker()
  214. {
  215. // This is only called while in m_cs
  216. m_hThread = CreateThread(NULL, // lpThreadAttributes
  217. 0, // dwStackSize
  218. (LPTHREAD_START_ROUTINE)&CRegEventProvider::Worker, // lpStartAddress
  219. this, // lpParameter
  220. 0, // dwCreationFlags
  221. &m_dwId); // lpThreadId
  222. }
  223. void CRegEventProvider::KillWorker()
  224. {
  225. // When this is called the following is true:
  226. // All waits have been unregistered .
  227. // All thread pool requests have been processed.
  228. // All CRegistryEventRequests in the queue are inactive.
  229. // m_cs has been entered.
  230. // Therefore no other threads will:
  231. // Place events in the queue.
  232. // Modify CRegistryEventRequests in the queue.
  233. // Create or destroy a worker thread.
  234. // So the worker thread will empty the queue of the remaining
  235. // inactive CRegistryEventRequests and then retrieve the null
  236. // event and return.
  237. EnqueueEvent((CRegistryEventRequest*)0);
  238. WaitForSingleObject(m_hThread, // hHandle
  239. INFINITE); // dwMilliseconds
  240. CloseHandle(m_hThread);
  241. m_hThread = 0;
  242. m_dwId = 0;
  243. }
  244. HRESULT CRegEventProvider::GetValuesForProp(QL_LEVEL_1_RPN_EXPRESSION* pExpr,
  245. CPropertyName& PropName,
  246. CWStringArray& awsVals)
  247. {
  248. awsVals.Empty();
  249. // Get the necessary query
  250. // =======================
  251. QL_LEVEL_1_RPN_EXPRESSION* pPropExpr = NULL;
  252. HRESULT hres = CQueryAnalyser::GetNecessaryQueryForProperty(pExpr,
  253. PropName, pPropExpr);
  254. if(FAILED(hres))
  255. {
  256. return hres;
  257. }
  258. if(pPropExpr == NULL)
  259. return WBEM_E_FAILED;
  260. // See if there are any tokens
  261. // ===========================
  262. if(pPropExpr->nNumTokens == 0)
  263. {
  264. delete pPropExpr;
  265. return WBEMESS_E_REGISTRATION_TOO_BROAD;
  266. }
  267. // Combine them all
  268. // ================
  269. for(int i = 0; i < pPropExpr->nNumTokens; i++)
  270. {
  271. QL_LEVEL_1_TOKEN& Token = pPropExpr->pArrayOfTokens[i];
  272. if(Token.nTokenType == QL1_NOT)
  273. {
  274. delete pPropExpr;
  275. return WBEMESS_E_REGISTRATION_TOO_BROAD;
  276. }
  277. else if(Token.nTokenType == QL1_AND || Token.nTokenType == QL1_OR)
  278. {
  279. // We treat them all as ORs
  280. // ========================
  281. }
  282. else
  283. {
  284. // This is a token
  285. // ===============
  286. if(Token.nOperator != QL1_OPERATOR_EQUALS)
  287. {
  288. delete pPropExpr;
  289. return WBEMESS_E_REGISTRATION_TOO_BROAD;
  290. }
  291. if(V_VT(&Token.vConstValue) != VT_BSTR)
  292. {
  293. delete pPropExpr;
  294. return WBEM_E_INVALID_QUERY;
  295. }
  296. // This token is a string equality. Add the string to the list
  297. // ===========================================================
  298. awsVals.Add(V_BSTR(&Token.vConstValue));
  299. }
  300. }
  301. delete pPropExpr;
  302. return WBEM_S_NO_ERROR;
  303. }
  304. HRESULT CRegEventProvider::SetTimerInstruction(CTimerInstruction* pInst)
  305. {
  306. //return m_pGenerator->Set(pInst, CWbemTime::GetZero());
  307. return S_OK;
  308. }
  309. HRESULT CRegEventProvider::RemoveTimerInstructions(
  310. CRegistryInstructionTest* pTest)
  311. {
  312. //return m_pGenerator->Remove(pTest);
  313. return S_OK;
  314. }
  315. HRESULT CRegEventProvider::RaiseEvent(IWbemClassObject* pEvent)
  316. {
  317. if(m_pSink)
  318. return m_pSink->Indicate(1, &pEvent);
  319. else
  320. return WBEM_S_NO_ERROR;
  321. }
  322. HKEY CRegEventProvider::TranslateHiveName(LPCWSTR wszName)
  323. {
  324. if(!_wcsicmp(wszName, L"HKEY_CLASSES_ROOT"))
  325. return HKEY_CLASSES_ROOT;
  326. /* Disallowed: different semantics for client and server
  327. else if(!_wcsicmp(wszName, L"HKEY_CURRENT_USER"))
  328. return HKEY_CURRENT_USER;
  329. */
  330. else if(!_wcsicmp(wszName, L"HKEY_LOCAL_MACHINE"))
  331. return HKEY_LOCAL_MACHINE;
  332. else if(!_wcsicmp(wszName, L"HKEY_USERS"))
  333. return HKEY_USERS;
  334. else if(!_wcsicmp(wszName, L"HKEY_PERFORMANCE_DATA"))
  335. return HKEY_PERFORMANCE_DATA;
  336. else if(!_wcsicmp(wszName, L"HKEY_CURRENT_CONFIG"))
  337. return HKEY_CURRENT_CONFIG;
  338. else if(!_wcsicmp(wszName, L"HKEY_DYN_DATA"))
  339. return HKEY_DYN_DATA;
  340. else
  341. return NULL;
  342. }
  343. DWORD CRegEventProvider::Worker(void* p)
  344. {
  345. CoInitializeEx(0,COINIT_MULTITHREADED);
  346. CRegEventProvider* pThis = (CRegEventProvider*)p;
  347. while(true)
  348. {
  349. WaitForSingleObject(pThis->m_hQueueSemaphore, // hHandle
  350. INFINITE); // dwMilliseconds
  351. CRegistryEventRequest *pReq = 0;
  352. {
  353. CInCritSec ics(&(pThis->m_csQueueLock));
  354. pReq = pThis->m_qEventQueue.Dequeue();
  355. }
  356. // If pReq is null then it is a signal for the thread to terminate.
  357. if (pReq)
  358. {
  359. pReq->ProcessEvent();
  360. // Dequeueing the request doesn't release it.
  361. // If it did then it might be deleted before we had a chance to use it.
  362. // Now we are done with it.
  363. pReq->Release();
  364. }
  365. else
  366. {
  367. break;
  368. }
  369. }
  370. CoUninitialize();
  371. return 0;
  372. }
  373. void CRegEventProvider::EnqueueEvent(CRegistryEventRequest *pReq)
  374. {
  375. {
  376. CInCritSec ics(&m_csQueueLock);
  377. // Placing the request in the queue AddRefs it.
  378. m_qEventQueue.Enqueue(pReq);
  379. }
  380. // Tell the worker thread that there is an item to process in the queue.
  381. ReleaseSemaphore(m_hQueueSemaphore, // hSemaphore
  382. 1, // lReleaseCount
  383. NULL); // lpPreviousCount
  384. }
  385. VOID CALLBACK CRegEventProvider::EnqueueEvent(PVOID lpParameter,
  386. BOOLEAN TimerOrWaitFired)
  387. {
  388. CRegistryEventRequest *pReq = (CRegistryEventRequest*) lpParameter;
  389. CRegEventProvider *pProv = pReq->GetProvider();
  390. pProv->EnqueueEvent(pReq);
  391. }
  392. const CLSID CLSID_RegistryEventProvider =
  393. {0xfa77a74e,0xe109,0x11d0,{0xad,0x6e,0x00,0xc0,0x4f,0xd8,0xfd,0xff}};
  394. IUnknown* CRegEventProviderFactory::CreateImpObj()
  395. {
  396. return (IWbemEventProvider*) new CRegEventProvider;
  397. }
  398. STDMETHODIMP CRegEventProvider::NewQuery(DWORD dwId,
  399. WBEM_WSTR wszLanguage,
  400. WBEM_WSTR wszQuery)
  401. {
  402. HRESULT hres;
  403. CancelQuery(dwId);
  404. // Parse the query
  405. // ===============
  406. CTextLexSource Source(wszQuery);
  407. QL1_Parser Parser(&Source);
  408. QL_LEVEL_1_RPN_EXPRESSION* pExpr;
  409. if(Parser.Parse(&pExpr))
  410. {
  411. return WBEM_E_INVALID_QUERY;
  412. }
  413. CDeleteMe<QL_LEVEL_1_RPN_EXPRESSION> dm(pExpr);
  414. // Check the class
  415. // ===============
  416. int nEventType;
  417. if(!_wcsicmp(pExpr->bsClassName, REG_VALUE_EVENT_CLASS))
  418. {
  419. nEventType = e_RegValueChange;
  420. }
  421. else if(!_wcsicmp(pExpr->bsClassName, REG_KEY_EVENT_CLASS))
  422. {
  423. nEventType = e_RegKeyChange;
  424. }
  425. else if(!_wcsicmp(pExpr->bsClassName, REG_TREE_EVENT_CLASS))
  426. {
  427. nEventType = e_RegTreeChange;
  428. }
  429. else
  430. {
  431. // No such class
  432. // =============
  433. return WBEM_E_INVALID_QUERY;
  434. }
  435. // Check tolerance on Win95
  436. // ========================
  437. if(!IsNT() && pExpr->Tolerance.m_bExact)
  438. {
  439. return WBEMESS_E_REGISTRATION_TOO_PRECISE;
  440. }
  441. // Extract the values of hive from the query
  442. // =========================================
  443. CPropertyName Name;
  444. Name.AddElement(REG_HIVE_PROPERTY_NAME);
  445. CWStringArray awsHiveVals;
  446. hres = GetValuesForProp(pExpr, Name, awsHiveVals);
  447. if(FAILED(hres)) return hres;
  448. // Translate them to real hives
  449. // ============================
  450. CUniquePointerArray<HKEY> aHives;
  451. for(int i = 0; i < awsHiveVals.Size(); i++)
  452. {
  453. HKEY hHive = TranslateHiveName(awsHiveVals[i]);
  454. if(hHive == NULL)
  455. {
  456. return WBEM_E_INVALID_QUERY;
  457. }
  458. aHives.Add(new HKEY(hHive));
  459. }
  460. // Extract the values of key from the query
  461. // ========================================
  462. Name.Empty();
  463. if(nEventType == e_RegTreeChange)
  464. {
  465. Name.AddElement(REG_ROOT_PROPERTY_NAME);
  466. }
  467. else
  468. {
  469. Name.AddElement(REG_KEY_PROPERTY_NAME);
  470. }
  471. CWStringArray awsKeyVals;
  472. hres = GetValuesForProp(pExpr, Name, awsKeyVals);
  473. if(FAILED(hres))
  474. {
  475. return hres;
  476. }
  477. CWStringArray awsValueVals;
  478. if(nEventType == e_RegValueChange)
  479. {
  480. // Extract the values for the value
  481. // ================================
  482. Name.Empty();
  483. Name.AddElement(REG_VALUE_PROPERTY_NAME);
  484. hres = GetValuesForProp(pExpr, Name, awsValueVals);
  485. if(FAILED(hres))
  486. {
  487. return hres;
  488. }
  489. }
  490. HRESULT hresGlobal = WBEM_E_INVALID_QUERY;
  491. {
  492. CInCritSec ics(&m_cs); // do this in a critical section
  493. // Go through every combination of the above and create requests
  494. // =============================================================
  495. for(int nHiveIndex = 0; nHiveIndex < aHives.GetSize(); nHiveIndex++)
  496. {
  497. HKEY hHive = *aHives[nHiveIndex];
  498. LPWSTR wszHive = awsHiveVals[nHiveIndex];
  499. for(int nKeyIndex = 0; nKeyIndex < awsKeyVals.Size(); nKeyIndex++)
  500. {
  501. LPWSTR wszKey = awsKeyVals[nKeyIndex];
  502. if(nEventType == e_RegValueChange)
  503. {
  504. for(int nValueIndex = 0; nValueIndex < awsValueVals.Size();
  505. nValueIndex++)
  506. {
  507. LPWSTR wszValue = awsValueVals[nValueIndex];
  508. CRegistryEventRequest* pReq =
  509. new CRegistryValueEventRequest(this,
  510. pExpr->Tolerance,
  511. dwId, hHive, wszHive, wszKey, wszValue);
  512. if(pReq->IsOK())
  513. {
  514. HRESULT hres = AddRequest(pReq);
  515. if(SUCCEEDED(hres))
  516. hresGlobal = hres;
  517. }
  518. else
  519. {
  520. DEBUGTRACE((LOG_ESS, "Invalid registration: key "
  521. "%S, value %S\n", wszKey, wszValue));
  522. delete pReq;
  523. }
  524. }
  525. }
  526. else
  527. {
  528. // Value-less request
  529. // ==================
  530. CRegistryEventRequest* pReq;
  531. if(nEventType == e_RegKeyChange)
  532. {
  533. pReq = new CRegistryKeyEventRequest(this,
  534. pExpr->Tolerance,
  535. dwId, hHive, wszHive, wszKey);
  536. }
  537. else
  538. {
  539. pReq = new CRegistryTreeEventRequest(this,
  540. pExpr->Tolerance,
  541. dwId, hHive, wszHive, wszKey);
  542. }
  543. if(pReq->IsOK())
  544. {
  545. hres = AddRequest(pReq);
  546. if(SUCCEEDED(hres))
  547. hresGlobal = hres;
  548. }
  549. else
  550. {
  551. DEBUGTRACE((LOG_ESS, "Invalid registration: key %S\n",
  552. wszKey));
  553. delete pReq;
  554. }
  555. }
  556. }
  557. }
  558. } // out of critical section
  559. return hresGlobal;
  560. }
  561. STDMETHODIMP CRegEventProvider::AccessCheck(WBEM_CWSTR wszLanguage,
  562. WBEM_CWSTR wszQuery,
  563. long lSidLength,
  564. const BYTE* aSid)
  565. {
  566. HRESULT hres;
  567. PSID pSid = (PSID)aSid;
  568. HANDLE hToken = NULL;
  569. if(pSid == NULL)
  570. {
  571. //
  572. // Access check based on the thread
  573. //
  574. hres = WbemCoImpersonateClient();
  575. if(FAILED(hres))
  576. return hres;
  577. BOOL bRes = OpenThreadToken(GetCurrentThread(), // ThreadHandle
  578. TOKEN_READ, // DesiredAccess
  579. TRUE, // OpenAsSelf
  580. &hToken); // TokenHandle
  581. WbemCoRevertToSelf();
  582. if(!bRes)
  583. {
  584. return WBEM_E_ACCESS_DENIED;
  585. }
  586. }
  587. CCloseMe cm1(hToken);
  588. // Parse the query
  589. // ===============
  590. CTextLexSource Source(wszQuery);
  591. QL1_Parser Parser(&Source);
  592. QL_LEVEL_1_RPN_EXPRESSION* pExpr;
  593. if(Parser.Parse(&pExpr))
  594. {
  595. return WBEM_E_INVALID_QUERY;
  596. }
  597. CDeleteMe<QL_LEVEL_1_RPN_EXPRESSION> dm(pExpr);
  598. // Check the class
  599. // ===============
  600. int nEventType;
  601. if(!_wcsicmp(pExpr->bsClassName, REG_VALUE_EVENT_CLASS))
  602. {
  603. nEventType = e_RegValueChange;
  604. }
  605. else if(!_wcsicmp(pExpr->bsClassName, REG_KEY_EVENT_CLASS))
  606. {
  607. nEventType = e_RegKeyChange;
  608. }
  609. else if(!_wcsicmp(pExpr->bsClassName, REG_TREE_EVENT_CLASS))
  610. {
  611. nEventType = e_RegTreeChange;
  612. }
  613. else
  614. {
  615. // No such class
  616. // =============
  617. return WBEM_E_INVALID_QUERY;
  618. }
  619. // Extract the values of hive from the query
  620. // =========================================
  621. CPropertyName Name;
  622. Name.AddElement(REG_HIVE_PROPERTY_NAME);
  623. CWStringArray awsHiveVals;
  624. hres = GetValuesForProp(pExpr, Name, awsHiveVals);
  625. if(FAILED(hres)) return hres;
  626. // Translate them to real hives
  627. // ============================
  628. CUniquePointerArray<HKEY> aHives;
  629. for(int i = 0; i < awsHiveVals.Size(); i++)
  630. {
  631. HKEY hHive = TranslateHiveName(awsHiveVals[i]);
  632. if(hHive == NULL)
  633. {
  634. return WBEM_E_INVALID_QUERY;
  635. }
  636. aHives.Add(new HKEY(hHive));
  637. }
  638. // Extract the values of key from the query
  639. // ========================================
  640. Name.Empty();
  641. if(nEventType == e_RegTreeChange)
  642. {
  643. Name.AddElement(REG_ROOT_PROPERTY_NAME);
  644. }
  645. else
  646. {
  647. Name.AddElement(REG_KEY_PROPERTY_NAME);
  648. }
  649. CWStringArray awsKeyVals;
  650. hres = GetValuesForProp(pExpr, Name, awsKeyVals);
  651. if(FAILED(hres))
  652. {
  653. return hres;
  654. }
  655. HRESULT hresGlobal = WBEM_E_INVALID_QUERY;
  656. // Go through every combination of the above and create requests
  657. // =============================================================
  658. for(int nHiveIndex = 0; nHiveIndex < aHives.GetSize(); nHiveIndex++)
  659. {
  660. HKEY hHive = *aHives[nHiveIndex];
  661. LPWSTR wszHive = awsHiveVals[nHiveIndex];
  662. for(int nKeyIndex = 0; nKeyIndex < awsKeyVals.Size(); nKeyIndex++)
  663. {
  664. LPWSTR wszKey = awsKeyVals[nKeyIndex];
  665. // Get that key's security
  666. // =======================
  667. HKEY hKey;
  668. long lRes = RegOpenKeyExW(hHive, // hKey
  669. wszKey, // lpSubKey
  670. 0, // ulOptions
  671. READ_CONTROL, // samDesired
  672. &hKey); // phkResult
  673. if(lRes)
  674. return WBEM_E_NOT_FOUND;
  675. CRegCloseMe cm2(hKey);
  676. DWORD dwLen = 0;
  677. lRes = RegGetKeySecurity(hKey, // hKey
  678. OWNER_SECURITY_INFORMATION |
  679. GROUP_SECURITY_INFORMATION |
  680. DACL_SECURITY_INFORMATION, // SecurityInformation
  681. NULL, // pSecurityDescriptor
  682. &dwLen); // lpcbSecurityDescriptor
  683. if(lRes != ERROR_INSUFFICIENT_BUFFER)
  684. return WBEM_E_FAILED;
  685. PSECURITY_DESCRIPTOR pDesc = (PSECURITY_DESCRIPTOR)new BYTE[dwLen];
  686. if(pDesc == NULL)
  687. return WBEM_E_OUT_OF_MEMORY;
  688. CVectorDeleteMe<BYTE> vdm((BYTE*)pDesc);
  689. lRes = RegGetKeySecurity(hKey,
  690. OWNER_SECURITY_INFORMATION |
  691. GROUP_SECURITY_INFORMATION |
  692. DACL_SECURITY_INFORMATION,
  693. pDesc,
  694. &dwLen);
  695. if(lRes)
  696. return WBEM_E_FAILED;
  697. //
  698. // Check permissions differently depending on whether we have a SID
  699. // or an actual token
  700. //
  701. if(pSid)
  702. {
  703. //
  704. // We have a SID --- walk the ACL
  705. //
  706. //
  707. // Extract the ACL
  708. //
  709. PACL pAcl = NULL;
  710. BOOL bAclPresent, bAclDefaulted;
  711. if(!GetSecurityDescriptorDacl(pDesc, // pSecurityDescriptor
  712. &bAclPresent, // lpbDaclPresent
  713. &pAcl, // pDacl
  714. &bAclDefaulted))// lpbDaclDefaulted
  715. {
  716. return WBEM_E_FAILED;
  717. }
  718. if(bAclPresent)
  719. {
  720. //
  721. // This is our own ACL walker
  722. //
  723. DWORD dwAccessMask;
  724. NTSTATUS st = GetAccessMask((PSID)pSid, pAcl,
  725. &dwAccessMask);
  726. if(st)
  727. {
  728. ERRORTRACE((LOG_ESS, "Registry event provider unable "
  729. "to retrieve access mask for the creator of "
  730. "registration %S: NT status %d.\n"
  731. "Registration disabled\n", wszQuery));
  732. return WBEM_E_FAILED;
  733. }
  734. if((dwAccessMask & KEY_NOTIFY) == 0)
  735. return WBEM_E_ACCESS_DENIED;
  736. }
  737. }
  738. else
  739. {
  740. //
  741. // We have a token --- use AccessCheck
  742. //
  743. //
  744. // Construct generic mapping for registry keys
  745. //
  746. GENERIC_MAPPING map;
  747. map.GenericRead = KEY_READ;
  748. map.GenericWrite = KEY_WRITE;
  749. map.GenericExecute = KEY_EXECUTE;
  750. map.GenericAll = KEY_ALL_ACCESS;
  751. //
  752. // Construct privilege array receptacle
  753. //
  754. PRIVILEGE_SET ps[10];
  755. DWORD dwSize = 10 * sizeof(PRIVILEGE_SET);
  756. DWORD dwGranted;
  757. BOOL bResult;
  758. BOOL bOK = ::AccessCheck(pDesc, // pSecurityDescriptor
  759. hToken, // ClientToken
  760. KEY_NOTIFY, // DesiredAccess
  761. &map, // GenericMapping
  762. ps, // PrivilegeSet
  763. &dwSize, // PrivilegeSetLength
  764. &dwGranted, // GrantedAccess
  765. &bResult); // AccessStatus
  766. if(!bOK || !bResult)
  767. return WBEM_E_ACCESS_DENIED;
  768. }
  769. }
  770. }
  771. return WBEM_S_NO_ERROR;
  772. }