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.

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