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.

2246 lines
59 KiB

  1. //=============================================================================
  2. //
  3. // Copyright (c) 1996-1999, Microsoft Corporation, All rights reserved
  4. //
  5. // ESS.CPP
  6. //
  7. // Implements the class that contains all the fuctionality of the ESS by
  8. // virtue of containing all the necessary components.
  9. //
  10. // See ess.h for documentation
  11. //
  12. // History:
  13. //
  14. // 11/27/96 a-levn Compiles.
  15. // 1/6/97 a-levn Updated to initialize TSS.
  16. //
  17. //=============================================================================
  18. #include "precomp.h"
  19. #include <stdio.h>
  20. #include <wmimsg.h>
  21. #include "ess.h"
  22. #include "persistcfg.h"
  23. #include "WinMgmtR.h"
  24. #include "GenUtils.h" // For SetObjectAccess
  25. #include "NCEvents.h"
  26. #include "Quota.h"
  27. #define BOOT_PHASE_MS 60*2*1000
  28. #define WBEM_REG_ESS_ACTIVE_NAMESPACES __TEXT("List of event-active namespaces")
  29. #define WBEM_ESS_OPEN_FOR_BUSINESS_EVENT_NAME L"WBEM_ESS_OPEN_FOR_BUSINESS"
  30. // The use of this pointer to initialize parent class is valid in this context
  31. #pragma warning(disable : 4355)
  32. //
  33. // this guid is used to identify the MSMQ queues that are used for guaranteed
  34. // delivery. A type guid is a property of an MSMQ queue, so one can tell
  35. // by looking at an MSMQ queue if its an ess one or not.
  36. //
  37. // {555471B4-0BE3-4e42-A98B-347AF72898FA}
  38. //
  39. const CLSID g_guidQueueType =
  40. { 0x555471b4, 0xbe3, 0x4e42, {0xa9, 0x8b, 0x34, 0x7a, 0xf7, 0x28, 0x98, 0xfa}};
  41. #pragma warning(push)
  42. // not all control paths return due to infinite loop
  43. #pragma warning(disable:4715)
  44. DWORD DumpThread(CEss* pEss)
  45. {
  46. while(1)
  47. {
  48. FILE* f = fopen("c:\\stat.log", "a");
  49. if(f == NULL)
  50. return 1;
  51. pEss->DumpStatistics(f, 0);
  52. fclose(f);
  53. Sleep(10000);
  54. }
  55. return 0;
  56. }
  57. #pragma warning(pop)
  58. DWORD RegDeleteSubKeysW( HKEY hkey )
  59. {
  60. FILETIME ft;
  61. DWORD dwIndex=0;
  62. LONG lRes = ERROR_SUCCESS;
  63. LONG lResReturn = lRes;
  64. DWORD dwBuffSize = 256;
  65. DWORD cName = dwBuffSize;
  66. LPWSTR wszName = new WCHAR[dwBuffSize];
  67. if ( wszName == NULL )
  68. {
  69. return ERROR_NOT_ENOUGH_MEMORY;
  70. }
  71. CWStringArray awsKeysToDelete;
  72. //
  73. // enumerate through all subkeys and make recursive call.
  74. //
  75. while( lRes == ERROR_SUCCESS &&
  76. ( lRes=RegEnumKeyExW( hkey, dwIndex, wszName, &cName, NULL,
  77. NULL, NULL, &ft ) ) != ERROR_NO_MORE_ITEMS )
  78. {
  79. if ( lRes == ERROR_SUCCESS )
  80. {
  81. HKEY hkeySub;
  82. //
  83. // open key and make recursive call.
  84. //
  85. lRes = RegOpenKeyExW( hkey,
  86. wszName,
  87. 0,
  88. KEY_ALL_ACCESS,
  89. &hkeySub );
  90. if ( lRes == ERROR_SUCCESS )
  91. {
  92. lRes = RegDeleteSubKeysW( hkeySub );
  93. RegCloseKey( hkeySub );
  94. }
  95. //
  96. // defer deletion of key until we're done enumerating.
  97. //
  98. try
  99. {
  100. awsKeysToDelete.Add( wszName );
  101. }
  102. catch( CX_MemoryException )
  103. {
  104. lRes = ERROR_NOT_ENOUGH_MEMORY;
  105. }
  106. //
  107. // we want to try to keep going if we fail.
  108. //
  109. if ( lRes != ERROR_SUCCESS )
  110. {
  111. lResReturn = lRes;
  112. lRes = ERROR_SUCCESS;
  113. }
  114. dwIndex++;
  115. }
  116. else if ( lRes == ERROR_MORE_DATA )
  117. {
  118. dwBuffSize += 256;
  119. delete [] wszName;
  120. wszName = new WCHAR[dwBuffSize];
  121. if ( wszName == NULL )
  122. {
  123. lRes = ERROR_NOT_ENOUGH_MEMORY;
  124. }
  125. else
  126. {
  127. lRes = ERROR_SUCCESS;
  128. }
  129. }
  130. cName = dwBuffSize;
  131. }
  132. delete [] wszName;
  133. for( int i=0; i < awsKeysToDelete.Size(); i++ )
  134. {
  135. lRes = RegDeleteKeyW( hkey, awsKeysToDelete[i] );
  136. if ( lRes != ERROR_SUCCESS )
  137. {
  138. lResReturn = lRes;
  139. }
  140. }
  141. return lResReturn;
  142. }
  143. /****************************************************************************
  144. CProviderReloadRequest
  145. *****************************************************************************/
  146. class CProviderReloadRequest : public CExecRequest
  147. {
  148. protected:
  149. CEss* m_pEss;
  150. long m_lFlags;
  151. CWbemPtr<IWbemContext> m_pContext;
  152. WString m_wsNamespace;
  153. WString m_wsProvider;
  154. public:
  155. CProviderReloadRequest( CEss* pEss,
  156. long lFlags,
  157. IWbemContext* pContext,
  158. LPCWSTR wszNamespace,
  159. LPCWSTR wszProvider )
  160. : m_pEss( pEss ), m_lFlags( lFlags ), m_pContext( pContext ),
  161. m_wsNamespace(wszNamespace), m_wsProvider( wszProvider ) {}
  162. HRESULT Execute();
  163. };
  164. HRESULT CProviderReloadRequest::Execute()
  165. {
  166. HRESULT hr;
  167. _DBG_ASSERT( GetCurrentEssThreadObject() == NULL );
  168. SetCurrentEssThreadObject( m_pContext );
  169. if ( GetCurrentEssThreadObject() != NULL )
  170. {
  171. hr = m_pEss->ReloadProvider( m_lFlags,
  172. m_wsNamespace,
  173. m_wsProvider );
  174. delete GetCurrentEssThreadObject();
  175. ClearCurrentEssThreadObject();
  176. }
  177. else
  178. {
  179. hr = WBEM_E_OUT_OF_MEMORY;
  180. }
  181. return hr;
  182. }
  183. /****************************************************************************
  184. CEssProvSSSink
  185. *****************************************************************************/
  186. class CEssProvSSSink : public CUnkBase<_IWmiProvSSSink, &IID__IWmiProvSSSink >
  187. {
  188. CEss* m_pEss;
  189. public:
  190. CEssProvSSSink( CEss* pEss ) : m_pEss( pEss ),
  191. CUnkBase< _IWmiProvSSSink, &IID__IWmiProvSSSink >( NULL ) { }
  192. STDMETHOD(Synchronize)( long lFlags,
  193. IWbemContext* pContext,
  194. LPCWSTR wszNamespace,
  195. LPCWSTR wszProvider );
  196. };
  197. STDMETHODIMP CEssProvSSSink::Synchronize( long lFlags,
  198. IWbemContext* pContext,
  199. LPCWSTR wszNamespace,
  200. LPCWSTR wszProvider )
  201. {
  202. HRESULT hr;
  203. CProviderReloadRequest* pReq;
  204. try
  205. {
  206. pReq = new CProviderReloadRequest( m_pEss,
  207. lFlags,
  208. pContext,
  209. wszNamespace,
  210. wszProvider );
  211. }
  212. catch( CX_MemoryException )
  213. {
  214. pReq = NULL;
  215. }
  216. if ( pReq != NULL )
  217. {
  218. hr = m_pEss->Enqueue( pReq );
  219. if ( FAILED(hr) )
  220. {
  221. delete pReq;
  222. }
  223. }
  224. else
  225. {
  226. hr = WBEM_E_OUT_OF_MEMORY;
  227. }
  228. return hr;
  229. }
  230. /***************************************************************************
  231. CNamespaceInitRequest - Used to execute a single namespace initialize. It
  232. can be set to perform various stages of Namespace initialization.
  233. ****************************************************************************/
  234. class CNamespaceInitRequest : public CExecRequest
  235. {
  236. protected:
  237. BOOL m_bActiveOnStart;
  238. CWbemPtr<CEssNamespace> m_pNamespace;
  239. CWbemPtr<IWbemContext> m_pContext;
  240. public:
  241. CNamespaceInitRequest( CEssNamespace* pNamespace, BOOL bActiveOnStart )
  242. : m_pNamespace(pNamespace), m_bActiveOnStart( bActiveOnStart )
  243. {
  244. m_pContext = GetCurrentEssContext();
  245. }
  246. HRESULT Execute()
  247. {
  248. HRESULT hr = WBEM_S_NO_ERROR;
  249. _DBG_ASSERT( GetCurrentEssThreadObject() == NULL );
  250. SetCurrentEssThreadObject( m_pContext );
  251. if ( GetCurrentEssThreadObject() != NULL )
  252. {
  253. //
  254. // if this namespace was active on boot, then it has already had
  255. // its Initialize() called.
  256. //
  257. if ( !m_bActiveOnStart )
  258. {
  259. hr = m_pNamespace->Initialize();
  260. }
  261. if ( SUCCEEDED(hr) )
  262. {
  263. hr = m_pNamespace->CompleteInitialization();
  264. }
  265. m_pNamespace->MarkAsInitialized( hr );
  266. delete GetCurrentEssThreadObject();
  267. ClearCurrentEssThreadObject();
  268. }
  269. else
  270. {
  271. hr = WBEM_E_OUT_OF_MEMORY;
  272. }
  273. //
  274. // if we're initializing because the namespace was active on
  275. // startup then notify ess that we're done because its waiting
  276. // for all active namespaces to finish initializing.
  277. //
  278. if ( m_bActiveOnStart )
  279. {
  280. m_pNamespace->GetEss()->NotifyActiveNamespaceInitComplete();
  281. }
  282. if(FAILED(hr))
  283. {
  284. ERRORTRACE((LOG_ESS, "ESS failed to initialize a namespace "
  285. "'%S'. Error code 0x%X\n", m_pNamespace->GetName(), hr));
  286. }
  287. return hr;
  288. }
  289. };
  290. /**************************************************************************
  291. CInitActiveNamespacesRequest - Used to initialize 1 or more active event
  292. namespaces. An active event namespace is one that was active on the last
  293. shutdown. The reason for initialization of multiple namespaces together is
  294. that the Stage1 Initialization of dependent active namespaces must complete
  295. before the Stage2 Initialization of any one of them. This is so all
  296. inter-namespace subscriptions can be put in place before event providers
  297. are activated in any one of them. Enforcing that all stage1 initialization
  298. of dependent active namespaces does not cause a problem of all namespaces
  299. being doomed by one faulty class provider in any single namespace because
  300. stage1 init is guaranteed not to access any providers. All stage2 init of
  301. dependent active namespace, which may access providers, is performed
  302. asynchronously.
  303. ****************************************************************************/
  304. class CInitActiveNamespacesRequest : public CExecRequest
  305. {
  306. protected:
  307. CEss* m_pEss;
  308. CRefedPointerArray<CEssNamespace> m_apNamespaces;
  309. CWbemPtr<IWbemContext> m_pContext;
  310. public:
  311. CInitActiveNamespacesRequest( CEss* pEss ) : m_pEss(pEss)
  312. {
  313. m_pContext = GetCurrentEssContext();
  314. }
  315. int GetNumNamespaces() { return m_apNamespaces.GetSize(); }
  316. void Reset()
  317. {
  318. m_apNamespaces.RemoveAll();
  319. }
  320. HRESULT Add( CEssNamespace* pNamespace )
  321. {
  322. if ( m_apNamespaces.Add( pNamespace ) < 0 )
  323. {
  324. return WBEM_E_OUT_OF_MEMORY;
  325. }
  326. return WBEM_S_NO_ERROR;
  327. }
  328. HRESULT Execute()
  329. {
  330. HRESULT hr;
  331. HRESULT hrGlobal = WBEM_S_NO_ERROR;
  332. _DBG_ASSERT( GetCurrentEssThreadObject() == NULL );
  333. SetCurrentEssThreadObject( m_pContext );
  334. if ( GetCurrentEssThreadObject() == NULL )
  335. {
  336. for( int i=0; i < m_apNamespaces.GetSize(); i++ )
  337. {
  338. m_pEss->NotifyActiveNamespaceInitComplete();
  339. }
  340. return WBEM_E_OUT_OF_MEMORY;
  341. }
  342. for( int i=0; i < m_apNamespaces.GetSize(); i++ )
  343. {
  344. hr = m_apNamespaces[i]->Initialize();
  345. if ( FAILED(hr) )
  346. {
  347. ERRORTRACE((LOG_ESS, "ESS failed to initialize active "
  348. "namespace '%S'. Error code 0x%x\n",
  349. m_apNamespaces[i]->GetName(), hr ));
  350. m_apNamespaces[i]->MarkAsInitialized(hr);
  351. m_apNamespaces.SetAt(i, NULL);
  352. m_pEss->NotifyActiveNamespaceInitComplete();
  353. hrGlobal = hr;
  354. }
  355. }
  356. for( int i=0; i < m_apNamespaces.GetSize(); i++ )
  357. {
  358. if ( m_apNamespaces[i] == NULL )
  359. {
  360. continue;
  361. }
  362. CNamespaceInitRequest* pReq;
  363. pReq = new CNamespaceInitRequest( m_apNamespaces[i], TRUE );
  364. if ( pReq != NULL )
  365. {
  366. hr = m_pEss->Enqueue( pReq );
  367. if (FAILED(hr))
  368. {
  369. delete pReq;
  370. }
  371. }
  372. else
  373. {
  374. hr = WBEM_E_OUT_OF_MEMORY;
  375. }
  376. if ( FAILED(hr) )
  377. {
  378. ERRORTRACE((LOG_ESS, "ESS failed to issue request for "
  379. "completion of init for namespace '%S'. HR=0x%x\n",
  380. m_apNamespaces[i]->GetName(), hr ));
  381. m_apNamespaces[i]->MarkAsInitialized( hr );
  382. m_pEss->NotifyActiveNamespaceInitComplete();
  383. hrGlobal = hr;
  384. }
  385. }
  386. _DBG_ASSERT( GetCurrentEssContext() == m_pContext );
  387. delete GetCurrentEssThreadObject();
  388. ClearCurrentEssThreadObject();
  389. return hrGlobal;
  390. }
  391. };
  392. inline LPWSTR NormalizeNamespaceString( LPCWSTR wszName )
  393. {
  394. int cLen = wcslen( wszName ) + 5; // 5 is for '\\.\' + '\0'
  395. LPWSTR wszNormName = new WCHAR[cLen];
  396. if ( wszNormName == NULL )
  397. {
  398. return NULL;
  399. }
  400. if ( wcsncmp( wszName, L"\\\\", 2 ) == 0 ||
  401. wcsncmp( wszName, L"//", 2 ) == 0 )
  402. {
  403. StringCchCopyW( wszNormName, cLen, wszName );
  404. }
  405. else
  406. {
  407. StringCchCopyW( wszNormName, cLen, L"\\\\.\\" );
  408. StringCchCatW( wszNormName, cLen, wszName );
  409. }
  410. //
  411. // also convert all backwards slashes to forward slashes so that the
  412. // normalized name can serve as both a valid wmi namespace string and as
  413. // a valid persistent string ( wrt msmq and registry keys ).
  414. //
  415. WCHAR* pch = wszNormName;
  416. while( *pch != '\0' )
  417. {
  418. if ( *pch == '\\' )
  419. {
  420. *pch = '/';
  421. }
  422. pch++;
  423. }
  424. return wszNormName;
  425. }
  426. //******************************************************************************
  427. // public
  428. //
  429. // See ess.h for documentation
  430. //
  431. //******************************************************************************
  432. CEss::CEss() : m_pLocator(NULL), m_pCoreServices(NULL), m_Queue(this),
  433. m_TimerGenerator(this), m_hExitBootPhaseTimer(NULL),
  434. m_wszServerName(NULL), m_lObjectCount(0), m_lNumActiveNamespaces(0),
  435. m_hReadyEvent(NULL), m_pProvSS(NULL), m_bLastCallForCoreCalled(FALSE),
  436. m_pProvSSSink(NULL), m_pTokenCache(NULL), m_pDecorator(NULL),
  437. m_hRecoveryThread(NULL), m_lOutstandingActiveNamespaceInit(0),
  438. m_bMSMQDisabled(FALSE),
  439. m_LimitControl(LOG_ESS, L"events held for consumers",
  440. L"SOFTWARE\\Microsoft\\WBEM\\CIMOM",
  441. L"Low Threshold On Events (B)",
  442. L"High Threshold On Events (B)",
  443. L"Max Wait On Events (ms)")
  444. {
  445. // Set the defaults for the limit control and read it from the registry
  446. // ====================================================================
  447. m_LimitControl.SetMin(10000000);
  448. m_LimitControl.SetMax(20000000);
  449. m_LimitControl.SetSleepAtMax(2000);
  450. m_LimitControl.Reread();
  451. InitNCEvents();
  452. }
  453. //******************************************************************************
  454. // public
  455. //
  456. // See ess.h for documentation
  457. //
  458. //******************************************************************************
  459. HRESULT CEss::LastCallForCore(LONG lIsSystemShutdown)
  460. {
  461. m_bLastCallForCoreCalled = TRUE;
  462. // Shut down the timer generator (needs persistence)
  463. // =================================================
  464. m_TimerGenerator.SaveAndRemove(lIsSystemShutdown);
  465. return WBEM_S_NO_ERROR;
  466. }
  467. HRESULT CEss::Shutdown(BOOL bIsSystemShutdown)
  468. {
  469. HRESULT hres;
  470. _DBG_ASSERT(m_bLastCallForCoreCalled);
  471. if ( m_hReadyEvent != NULL )
  472. {
  473. //
  474. // we must reset the ready event before parking the namespace.
  475. // this way providers can maybe tell why they are being shutdown.
  476. //
  477. ResetEvent( m_hReadyEvent );
  478. }
  479. // Get persistent storage up-to-date
  480. // =================================
  481. std::vector< CWbemPtr<CEssNamespace>,
  482. wbem_allocator< CWbemPtr<CEssNamespace> > > Namespaces;
  483. {
  484. CInCritSec ics(&m_cs);
  485. m_TimerGenerator.SaveAndRemove((LONG)FALSE);
  486. TNamespaceIterator it;
  487. for( it = m_mapNamespaces.begin();it != m_mapNamespaces.end(); it++ )
  488. Namespaces.push_back( it->second );
  489. }
  490. for( int i=0; i < Namespaces.size(); i++ )
  491. {
  492. try {
  493. Namespaces[i]->Park();
  494. } catch (CX_Exception &){};
  495. }
  496. return WBEM_S_NO_ERROR;
  497. }
  498. HRESULT CEss::RequestStartOnBoot(BOOL bStart)
  499. {
  500. CPersistentConfig per;
  501. per.SetPersistentCfgValue(PERSIST_CFGVAL_CORE_ESS_NEEDS_LOADING, bStart);
  502. SaveActiveNamespaceList();
  503. return WBEM_S_NO_ERROR;
  504. }
  505. CEss::~CEss()
  506. {
  507. if( GetCurrentEssThreadObject() == NULL )
  508. {
  509. SetCurrentEssThreadObject(NULL);
  510. }
  511. m_EventLog.Close();
  512. if(m_pTokenCache)
  513. {
  514. m_pTokenCache->Shutdown();
  515. }
  516. //
  517. // make sure that recovery has finished.
  518. //
  519. if ( m_hRecoveryThread != NULL )
  520. {
  521. WaitForSingleObject( m_hRecoveryThread, INFINITE );
  522. CloseHandle( m_hRecoveryThread );
  523. m_hRecoveryThread = NULL;
  524. }
  525. //
  526. // Shutdown the quotas. This must be done before we cleanup the
  527. // namespaces because it uses the root namespace for registering
  528. // for quota change events.
  529. //
  530. g_quotas.Shutdown();
  531. m_TimerGenerator.Shutdown();
  532. // Clear the namespace map
  533. // =======================
  534. BOOL bLeft = TRUE;
  535. do
  536. {
  537. // Retrieve the next namespace object and remove it from the map
  538. // =============================================================
  539. CEssNamespace* pNamespace = NULL;
  540. {
  541. CInCritSec ics(&m_cs);
  542. TNamespaceIterator it = m_mapNamespaces.begin();
  543. if(it != m_mapNamespaces.end())
  544. {
  545. pNamespace = it->second;
  546. m_mapNamespaces.erase(it);
  547. }
  548. }
  549. // Shut it down if retrieved
  550. // =========================
  551. if(pNamespace)
  552. {
  553. pNamespace->Shutdown();
  554. pNamespace->Release();
  555. }
  556. // Check if any are left
  557. // =====================
  558. {
  559. CInCritSec ics(&m_cs);
  560. bLeft = !m_mapNamespaces.empty();
  561. }
  562. } while(bLeft);
  563. //
  564. // make sure we remove the callback timer so that we're sure that no
  565. // callbacks occur after we destruct. Make sure that we're not holding
  566. // the critsec at this point because their could be a deadlock, since
  567. // the callback could be executing right now and be waiting for the
  568. // critsec. We would then deadlock when calling DeleteTimerQueueTimer()
  569. //
  570. if ( m_hExitBootPhaseTimer != NULL )
  571. {
  572. DeleteTimerQueueTimer( NULL,
  573. m_hExitBootPhaseTimer,
  574. INVALID_HANDLE_VALUE );
  575. }
  576. m_Queue.Shutdown();
  577. delete GetCurrentEssThreadObject();
  578. ClearCurrentEssThreadObject();
  579. if ( m_pProvSS != NULL && m_pProvSSSink != NULL )
  580. {
  581. m_pProvSS->UnRegisterNotificationSink( 0, NULL, m_pProvSSSink );
  582. }
  583. CEventRepresentation::Shutdown();
  584. CEventAggregator::Shutdown();
  585. if(m_pLocator)
  586. m_pLocator->Release();
  587. if(m_pCoreServices)
  588. m_pCoreServices->Release();
  589. if(m_pProvSS)
  590. m_pProvSS->Release();
  591. if(m_pProvSSSink)
  592. m_pProvSSSink->Release();
  593. if(m_pDecorator)
  594. m_pDecorator->Release();
  595. delete [] m_wszServerName;
  596. m_pTokenCache->Release();
  597. CEssThreadObject::ClearSpecialContext();
  598. for( int i=0; i < m_aDeferredNSInitRequests.GetSize(); i++ )
  599. delete m_aDeferredNSInitRequests[i];
  600. DeinitNCEvents();
  601. m_Queue.Shutdown();
  602. if ( m_hReadyEvent != NULL )
  603. {
  604. CloseHandle( m_hReadyEvent );
  605. }
  606. }
  607. HRESULT CEss::SetNamespaceActive(LPCWSTR wszNamespace)
  608. {
  609. LONG lRes;
  610. HKEY hkeyEss, hkeyNamespace;
  611. DEBUGTRACE((LOG_ESS,"Namespace %S is becoming Active\n", wszNamespace));
  612. //
  613. // If this is the first active namespace, request that WinMgmt load us the
  614. // next time around
  615. //
  616. if(m_lNumActiveNamespaces++ == 0)
  617. {
  618. RequestStartOnBoot(TRUE);
  619. }
  620. //
  621. // open ess key.
  622. //
  623. lRes = RegOpenKeyExW( HKEY_LOCAL_MACHINE,
  624. WBEM_REG_ESS,
  625. 0,
  626. KEY_ALL_ACCESS,
  627. &hkeyEss );
  628. //
  629. // open or create namespace key.
  630. //
  631. if ( lRes == ERROR_SUCCESS )
  632. {
  633. lRes = RegCreateKeyExW( hkeyEss,
  634. wszNamespace,
  635. 0,
  636. NULL,
  637. REG_OPTION_NON_VOLATILE,
  638. KEY_ALL_ACCESS,
  639. NULL,
  640. &hkeyNamespace,
  641. NULL );
  642. if ( lRes == ERROR_SUCCESS )
  643. {
  644. RegCloseKey( hkeyNamespace );
  645. }
  646. RegCloseKey( hkeyEss );
  647. }
  648. if ( lRes != ERROR_SUCCESS )
  649. {
  650. ERRORTRACE((LOG_ESS,"Error adding active namespace key %S to "
  651. "registry. Res=%d\n", wszNamespace, lRes ));
  652. }
  653. return HRESULT_FROM_WIN32( lRes );
  654. }
  655. HRESULT CEss::SetNamespaceInactive(LPCWSTR wszNamespace)
  656. {
  657. LONG lRes;
  658. HKEY hkeyEss, hkeyNamespace;
  659. DEBUGTRACE((LOG_ESS,"Namespace %S is becoming Inactive\n", wszNamespace));
  660. //
  661. // If this is the last active namespace, request that WinMgmt not load us
  662. // the next time around
  663. //
  664. if(--m_lNumActiveNamespaces == 0)
  665. {
  666. RequestStartOnBoot(FALSE);
  667. }
  668. //
  669. // open ess key.
  670. //
  671. lRes = RegOpenKeyExW( HKEY_LOCAL_MACHINE,
  672. WBEM_REG_ESS,
  673. 0,
  674. KEY_ALL_ACCESS,
  675. &hkeyEss );
  676. //
  677. // delete namespace key
  678. //
  679. if ( lRes == ERROR_SUCCESS )
  680. {
  681. lRes = RegOpenKeyExW( hkeyEss,
  682. wszNamespace,
  683. 0,
  684. KEY_ALL_ACCESS,
  685. &hkeyNamespace );
  686. if ( lRes == ERROR_SUCCESS )
  687. {
  688. lRes = RegDeleteSubKeysW( hkeyNamespace );
  689. RegCloseKey( hkeyNamespace );
  690. }
  691. if ( lRes == ERROR_SUCCESS )
  692. {
  693. lRes = RegDeleteKeyW( hkeyEss, wszNamespace );
  694. }
  695. RegCloseKey( hkeyEss );
  696. }
  697. if ( lRes != ERROR_SUCCESS )
  698. {
  699. ERRORTRACE((LOG_ESS,"Error removing active namespace key %S from "
  700. "registry. Res=%d\n", wszNamespace, lRes ));
  701. }
  702. return HRESULT_FROM_WIN32(lRes);
  703. }
  704. HRESULT CEss::SaveActiveNamespaceList()
  705. {
  706. CWStringArray wsNamespaces;
  707. //
  708. // Iterate through the namespaces
  709. //
  710. DWORD dwTotalLen = 0;
  711. {
  712. CInCritSec ics(&m_cs);
  713. for(TNamespaceIterator it = m_mapNamespaces.begin();
  714. it != m_mapNamespaces.end(); it++)
  715. {
  716. if(it->second->IsNeededOnStartup())
  717. {
  718. LPCWSTR wszName = it->second->GetName();
  719. if(wsNamespaces.Add(wszName) < 0)
  720. return WBEM_E_OUT_OF_MEMORY;
  721. dwTotalLen += wcslen(wszName) + 1;
  722. }
  723. }
  724. }
  725. dwTotalLen += 1;
  726. //
  727. // Allocate a buffer for all of these strings and copy them all in,
  728. // separated by NULLs.
  729. //
  730. WCHAR* awcBuffer = new WCHAR[dwTotalLen];
  731. if(awcBuffer == NULL)
  732. return WBEM_E_OUT_OF_MEMORY;
  733. CVectorDeleteMe<WCHAR> vdm(awcBuffer);
  734. WCHAR* pwcCurrent = awcBuffer;
  735. for(int i = 0; i < wsNamespaces.Size(); i++)
  736. {
  737. LPCWSTR wszName = wsNamespaces[i];
  738. StringCchCopyW( pwcCurrent,
  739. dwTotalLen - (pwcCurrent-awcBuffer),
  740. wszName );
  741. pwcCurrent += wcslen(wszName)+1;
  742. }
  743. *pwcCurrent = NULL;
  744. //
  745. // Store this string in the registry
  746. //
  747. Registry r(WBEM_REG_WINMGMT);
  748. int nRes = r.SetBinary(WBEM_REG_ESS_ACTIVE_NAMESPACES, (byte*)awcBuffer,
  749. dwTotalLen * sizeof(WCHAR));
  750. if(nRes != Registry::no_error)
  751. return WBEM_E_FAILED;
  752. //
  753. // Return S_FALSE if no namespaces are active
  754. //
  755. if(wsNamespaces.Size() > 0)
  756. return S_OK;
  757. else
  758. return S_FALSE;
  759. }
  760. HRESULT CEss::Initialize( LPCWSTR wszServerName,
  761. long lFlags,
  762. _IWmiCoreServices* pCoreServices,
  763. IWbemDecorator* pDecorator )
  764. {
  765. HRESULT hres;
  766. try
  767. {
  768. m_EventLog.Open();
  769. hres = CoCreateInstance(CLSID_WbemTokenCache, NULL, CLSCTX_INPROC_SERVER,
  770. IID_IWbemTokenCache, (void**)&m_pTokenCache);
  771. if(FAILED(hres))
  772. {
  773. ERRORTRACE((LOG_ESS, "Cannot create a token cache: 0x%x\n", hres));
  774. return hres;
  775. }
  776. m_wszServerName = _new WCHAR[wcslen(wszServerName)+1];
  777. if(m_wszServerName == NULL)
  778. return WBEM_E_OUT_OF_MEMORY;
  779. StringCchCopyW( m_wszServerName, wcslen(wszServerName)+1, wszServerName );
  780. m_pCoreServices = pCoreServices;
  781. m_pCoreServices->AddRef();
  782. //
  783. // Get provider subsystem and register our callback with it.
  784. //
  785. hres = m_pCoreServices->GetProviderSubsystem(0, &m_pProvSS);
  786. if( SUCCEEDED(hres) )
  787. {
  788. m_pProvSSSink = new CEssProvSSSink( this );
  789. if ( m_pProvSSSink == NULL )
  790. {
  791. return WBEM_E_OUT_OF_MEMORY;
  792. }
  793. m_pProvSSSink->AddRef();
  794. hres = m_pProvSS->RegisterNotificationSink( 0, NULL, m_pProvSSSink );
  795. if ( FAILED(hres) )
  796. {
  797. ERRORTRACE((LOG_ESS, "Failed to register notification sink "
  798. "with provider subsystem: 0x%X\n",hres));
  799. }
  800. }
  801. else
  802. {
  803. ERRORTRACE((LOG_ESS, "No provider subsystem: 0x%X\n", hres));
  804. }
  805. // Store the "decorator"
  806. // =====================
  807. m_pDecorator = pDecorator;
  808. m_pDecorator->AddRef();
  809. CInObjectCount ioc(this);
  810. // Connect to the default namespace
  811. // ================================
  812. IWbemServices* pRoot;
  813. hres = m_pCoreServices->GetServices(L"root", NULL,NULL,
  814. WMICORE_FLAG_REPOSITORY | WMICORE_CLIENT_TYPE_ESS,
  815. IID_IWbemServices, (void**)&pRoot);
  816. if(FAILED(hres)) return hres;
  817. CReleaseMe rm1(pRoot);
  818. // Pre-load event classes
  819. // ======================
  820. hres = CEventRepresentation::Initialize(pRoot, pDecorator);
  821. if(FAILED(hres)) return hres;
  822. // Initialize aggregator
  823. // =====================
  824. CEventAggregator::Initialize(pRoot);
  825. // Initialize timer instructions
  826. // =============================
  827. CConsumerProviderWatchInstruction::staticInitialize(pRoot);
  828. CEventProviderWatchInstruction::staticInitialize(pRoot);
  829. CConsumerWatchInstruction::staticInitialize(pRoot);
  830. //
  831. // construct an event announcing to the world that ESS is open for business
  832. //
  833. //
  834. // Construct a security descriptor
  835. //
  836. CNtSecurityDescriptor SD;
  837. SID_IDENTIFIER_AUTHORITY idNtAuthority = SECURITY_NT_AUTHORITY;
  838. PSID pRawSid = NULL;
  839. if(!AllocateAndInitializeSid(&idNtAuthority, 2,
  840. SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,
  841. 0,0,0,0,0,0,&pRawSid))
  842. {
  843. return WBEM_E_OUT_OF_MEMORY;
  844. }
  845. CNtSid SidAdmins(pRawSid);
  846. FreeSid(pRawSid);
  847. pRawSid = NULL;
  848. SID_IDENTIFIER_AUTHORITY idWorldAuthority = SECURITY_WORLD_SID_AUTHORITY;
  849. if(!AllocateAndInitializeSid( &idWorldAuthority, 1,
  850. SECURITY_WORLD_RID,
  851. 0, 0,0,0,0,0,0,&pRawSid))
  852. {
  853. return WBEM_E_OUT_OF_MEMORY;
  854. }
  855. CNtSid SidEveryone(pRawSid);
  856. FreeSid(pRawSid);
  857. CNtAce AceAdmins(EVENT_ALL_ACCESS, ACCESS_ALLOWED_ACE_TYPE, 0, SidAdmins);
  858. CNtAce AceOthers(SYNCHRONIZE, ACCESS_ALLOWED_ACE_TYPE, 0, SidEveryone);
  859. CNtAcl Acl;
  860. if(!Acl.AddAce(&AceAdmins))
  861. return WBEM_E_OUT_OF_MEMORY;
  862. if(!Acl.AddAce(&AceOthers))
  863. return WBEM_E_OUT_OF_MEMORY;
  864. if(!SD.SetDacl(&Acl))
  865. return WBEM_E_OUT_OF_MEMORY;
  866. SECURITY_ATTRIBUTES sa;
  867. sa.nLength = sizeof sa;
  868. sa.lpSecurityDescriptor = SD.GetPtr();
  869. sa.bInheritHandle = FALSE;
  870. m_hReadyEvent = CreateEventW( &sa,
  871. TRUE,
  872. FALSE,
  873. WBEM_ESS_OPEN_FOR_BUSINESS_EVENT_NAME );
  874. if( m_hReadyEvent == NULL )
  875. {
  876. ERRORTRACE((LOG_ESS, "Unable to create 'ready' event: 0x%X\n",
  877. GetLastError()));
  878. return WBEM_E_CRITICAL_ERROR;
  879. }
  880. // Pre-load default namespace
  881. // ==========================
  882. LoadActiveNamespaces(pRoot, lFlags == WMIESS_INIT_REPOSITORY_RECOVERED );
  883. CTemporaryHeap::Compact();
  884. #ifdef __DUMP_STATISTICS
  885. #pragma message("Statistics dump in effect")
  886. DWORD dw;
  887. CloseHandle(CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)DumpThread,
  888. this, 0, &dw));
  889. #endif
  890. //
  891. // Initialize the quotas.
  892. //
  893. g_quotas.Init(this);
  894. }
  895. catch(...)
  896. {
  897. throw;
  898. return WBEM_E_OUT_OF_MEMORY;
  899. }
  900. return WBEM_S_NO_ERROR;
  901. }
  902. void CEss::NotifyActiveNamespaceInitComplete()
  903. {
  904. _DBG_ASSERT( m_lOutstandingActiveNamespaceInit > 0 );
  905. if ( InterlockedDecrement( &m_lOutstandingActiveNamespaceInit ) == 0 )
  906. {
  907. if ( SetEvent( m_hReadyEvent ) )
  908. {
  909. DEBUGTRACE((LOG_ESS,"ESS is now open for business.\n"));
  910. }
  911. else
  912. {
  913. ERRORTRACE((LOG_ESS,"ESS could not set ready event. res=%d\n",
  914. GetLastError() ));
  915. }
  916. }
  917. }
  918. HRESULT CEss::CreateNamespaceObject( LPCWSTR wszNormName,
  919. CEssNamespace** ppNamespace )
  920. {
  921. HRESULT hr;
  922. *ppNamespace = NULL;
  923. CWbemPtr<CEssNamespace> pNamespace = NULL;
  924. try
  925. {
  926. pNamespace = new CEssNamespace(this);
  927. }
  928. catch(CX_MemoryException)
  929. {
  930. return WBEM_E_OUT_OF_MEMORY;
  931. }
  932. if( pNamespace == NULL )
  933. {
  934. return WBEM_E_OUT_OF_MEMORY;
  935. }
  936. hr = pNamespace->PreInitialize( wszNormName );
  937. if ( FAILED(hr) )
  938. {
  939. return hr;
  940. }
  941. try
  942. {
  943. m_mapNamespaces[wszNormName] = pNamespace;
  944. }
  945. catch(CX_MemoryException)
  946. {
  947. return WBEM_E_OUT_OF_MEMORY;
  948. }
  949. pNamespace->AddRef(); // for the map
  950. pNamespace->AddRef();
  951. *ppNamespace = pNamespace;
  952. return WBEM_S_NO_ERROR;
  953. }
  954. HRESULT CEss::GetNamespaceObject( LPCWSTR wszName,
  955. BOOL bEnsureActivation,
  956. CEssNamespace** ppNamespace)
  957. {
  958. HRESULT hres;
  959. *ppNamespace = NULL;
  960. CWbemPtr<CEssNamespace> pNamespace;
  961. //
  962. // need to normalize namespace name
  963. //
  964. LPWSTR wszNormName = NormalizeNamespaceString( wszName );
  965. if ( wszNormName == NULL )
  966. {
  967. return WBEM_E_OUT_OF_MEMORY;
  968. }
  969. CVectorDeleteMe<WCHAR> dmwszNormName( wszNormName );
  970. {
  971. CInCritSec ics(&m_cs);
  972. //
  973. // Search the map
  974. //
  975. TNamespaceIterator it;
  976. try
  977. {
  978. it = m_mapNamespaces.find(wszNormName);
  979. }
  980. catch (CX_MemoryException &)
  981. {
  982. return WBEM_E_OUT_OF_MEMORY;
  983. };
  984. if(it != m_mapNamespaces.end())
  985. {
  986. // Found it
  987. // ========
  988. pNamespace = it->second;
  989. }
  990. else
  991. {
  992. // Not found --- create a new one
  993. // ==============================
  994. hres = CreateNamespaceObject( wszNormName, &pNamespace );
  995. if ( FAILED(hres) )
  996. {
  997. return hres;
  998. }
  999. }
  1000. }
  1001. //
  1002. // ensure that initialization is pending if necessary
  1003. //
  1004. if ( bEnsureActivation && pNamespace->MarkAsInitPendingIfQuiet() )
  1005. {
  1006. //
  1007. // kick off initialization for this namespace on another thread.
  1008. //
  1009. CNamespaceInitRequest* pReq;
  1010. pReq = new CNamespaceInitRequest( pNamespace, FALSE );
  1011. if ( pReq == NULL )
  1012. {
  1013. pNamespace->MarkAsInitialized( WBEM_E_OUT_OF_MEMORY );
  1014. return WBEM_E_OUT_OF_MEMORY;
  1015. }
  1016. hres = ScheduleNamespaceInitialize( pReq );
  1017. if ( FAILED(hres) )
  1018. {
  1019. delete pReq;
  1020. pNamespace->MarkAsInitialized( WBEM_E_OUT_OF_MEMORY );
  1021. return hres;
  1022. }
  1023. }
  1024. pNamespace->AddRef();
  1025. *ppNamespace = pNamespace;
  1026. return WBEM_S_NO_ERROR;
  1027. }
  1028. //
  1029. // Creates a namespace object for the specified namespace and adds it
  1030. // to the request object.
  1031. //
  1032. HRESULT CEss::PrepareNamespaceInitRequest( LPCWSTR wszNamespace,
  1033. CInitActiveNamespacesRequest* pRequest )
  1034. {
  1035. HRESULT hr = WBEM_S_NO_ERROR;
  1036. DEBUGTRACE((LOG_ESS,
  1037. "Preparing a namespace init request for active namespace %S\n",
  1038. wszNamespace ));
  1039. CWbemPtr<CEssNamespace> pNamespace;
  1040. LPWSTR wszNormName = NormalizeNamespaceString( wszNamespace );
  1041. if ( wszNormName != NULL )
  1042. {
  1043. hr = CreateNamespaceObject( wszNormName, &pNamespace );
  1044. if ( SUCCEEDED(hr) )
  1045. {
  1046. hr = pRequest->Add( pNamespace );
  1047. //
  1048. // make sure to tell the namespace that init is pending.
  1049. //
  1050. BOOL bIsPending = pNamespace->MarkAsInitPendingIfQuiet();
  1051. _DBG_ASSERT( bIsPending );
  1052. }
  1053. delete [] wszNormName;
  1054. }
  1055. else
  1056. {
  1057. hr = WBEM_E_OUT_OF_MEMORY;
  1058. }
  1059. if ( FAILED(hr) )
  1060. {
  1061. ERRORTRACE((LOG_ESS, "Error 0x%X occurred when preparing active "
  1062. "namespace %S for initialization \n", hr, wszNamespace ));
  1063. }
  1064. return hr;
  1065. }
  1066. //
  1067. // This method prepares a request object that will initialize the specified
  1068. // namespace and all descendent namespaces as if they were all active dependant
  1069. // namespaces. This is useful when the Active namespace information could not
  1070. // be obtained from the last shutdown.
  1071. //
  1072. HRESULT CEss::RecursivePrepareNamespaceInitRequests(
  1073. LPCWSTR wszNamespace,
  1074. IWbemServices* pSvc,
  1075. CInitActiveNamespacesRequest* pRequest )
  1076. {
  1077. HRESULT hr;
  1078. hr = PrepareNamespaceInitRequest( wszNamespace, pRequest );
  1079. if ( FAILED(hr) )
  1080. {
  1081. return hr;
  1082. }
  1083. //
  1084. // Enumerate all child namespaces and make recursive call for each
  1085. //
  1086. CWbemPtr<IEnumWbemClassObject> penumChildren;
  1087. hr = pSvc->CreateInstanceEnum( CWbemBSTR( L"__NAMESPACE" ),
  1088. 0,
  1089. GetCurrentEssContext(),
  1090. &penumChildren );
  1091. if( FAILED(hr) )
  1092. {
  1093. ERRORTRACE((LOG_ESS, "Error 0x%X occurred enumerating child "
  1094. "namespaces of namespace %S. Some child namespaces may not be "
  1095. "active\n", hr, wszNamespace ));
  1096. //
  1097. // don't treat this as error, since this namespace was created and
  1098. // added to the request. Just no more work to do here.
  1099. //
  1100. return WBEM_S_NO_ERROR;
  1101. }
  1102. DWORD dwRead;
  1103. IWbemClassObject* pChildObj;
  1104. while((hr=penumChildren->Next(INFINITE, 1, &pChildObj, &dwRead)) == S_OK)
  1105. {
  1106. VARIANT vName;
  1107. VariantInit(&vName);
  1108. CClearMe cm1(&vName);
  1109. hr = pChildObj->Get( L"Name", 0, &vName, NULL, NULL );
  1110. pChildObj->Release();
  1111. if( FAILED(hr) )
  1112. {
  1113. return hr;
  1114. }
  1115. if ( V_VT(&vName) != VT_BSTR )
  1116. {
  1117. return WBEM_E_CRITICAL_ERROR;
  1118. }
  1119. //
  1120. // form the full name of the namespace
  1121. //
  1122. WString wsFullName;
  1123. try
  1124. {
  1125. wsFullName = wszNamespace;
  1126. wsFullName += L"\\";
  1127. wsFullName += V_BSTR(&vName);
  1128. }
  1129. catch( CX_MemoryException )
  1130. {
  1131. return WBEM_E_OUT_OF_MEMORY;
  1132. }
  1133. //
  1134. // get the svc ptr for the namespace. Must be repository only.
  1135. //
  1136. CWbemPtr<IWbemServices> pChildSvc;
  1137. long lFlags = WMICORE_FLAG_REPOSITORY | WMICORE_CLIENT_TYPE_ESS;
  1138. hr = m_pCoreServices->GetServices( wsFullName,NULL,NULL,
  1139. lFlags,
  1140. IID_IWbemServices,
  1141. (void**)&pChildSvc );
  1142. if ( SUCCEEDED(hr) )
  1143. {
  1144. //
  1145. // make the recursive call.
  1146. //
  1147. RecursivePrepareNamespaceInitRequests( wsFullName,
  1148. pChildSvc,
  1149. pRequest );
  1150. }
  1151. else
  1152. {
  1153. ERRORTRACE((LOG_ESS,
  1154. "Failed to open child namespace %S in %S: 0x%x\n",
  1155. V_BSTR(&vName), wszNamespace, hr));
  1156. }
  1157. }
  1158. return WBEM_S_NO_ERROR;
  1159. }
  1160. //
  1161. // This method prepares namespace init requests for active namespaces. It
  1162. // uses persisted information to determine the active namespaces. Each
  1163. // ActiveNamespaceInit request may contain multiple namespaces. This allows
  1164. // dependent namespaces to be initialized together. For now, all active
  1165. // namespaces are treated as inter-dependent - so only one request will be
  1166. // added to the list. If there is no persisted information about active
  1167. // namespaces, then all existing namespaces are treated as active dependent
  1168. // ones.
  1169. //
  1170. HRESULT CEss::PrepareNamespaceInitRequests( IWbemServices* pRoot,
  1171. BOOL bRediscover,
  1172. InitActiveNsRequestList& aRequests)
  1173. {
  1174. HRESULT hr = WBEM_S_NO_ERROR;
  1175. CInitActiveNamespacesRequest* pReq;
  1176. pReq = new CInitActiveNamespacesRequest(this);
  1177. if ( pReq == NULL )
  1178. {
  1179. return WBEM_E_OUT_OF_MEMORY;
  1180. }
  1181. //
  1182. // Get the list of active namespaces from the registry
  1183. //
  1184. LONG lRes;
  1185. DWORD dwDisp;
  1186. HKEY hkeyEss, hkeyNamespace;
  1187. lRes = RegCreateKeyExW( HKEY_LOCAL_MACHINE,
  1188. WBEM_REG_ESS,
  1189. 0,
  1190. NULL,
  1191. REG_OPTION_NON_VOLATILE,
  1192. KEY_ALL_ACCESS,
  1193. NULL,
  1194. &hkeyEss,
  1195. &dwDisp );
  1196. if ( lRes == ERROR_SUCCESS )
  1197. {
  1198. if ( !bRediscover )
  1199. {
  1200. FILETIME ft;
  1201. DWORD dwIndex = 0;
  1202. DWORD dwBuffSize = 256;
  1203. LPWSTR wszName = new WCHAR[dwBuffSize];
  1204. DWORD cName = dwBuffSize;
  1205. if ( wszName == NULL )
  1206. {
  1207. hr = WBEM_E_OUT_OF_MEMORY;
  1208. }
  1209. while( SUCCEEDED(hr) && (lRes=RegEnumKeyExW( hkeyEss, dwIndex,
  1210. wszName, &cName, NULL,
  1211. NULL, NULL, &ft ) )
  1212. != ERROR_NO_MORE_ITEMS )
  1213. {
  1214. if ( lRes == ERROR_SUCCESS )
  1215. {
  1216. hr = PrepareNamespaceInitRequest( wszName, pReq );
  1217. dwIndex++;
  1218. }
  1219. else if ( lRes == ERROR_MORE_DATA )
  1220. {
  1221. dwBuffSize += 256;
  1222. delete [] wszName;
  1223. wszName = new WCHAR[dwBuffSize];
  1224. if ( wszName == NULL )
  1225. {
  1226. hr = WBEM_E_OUT_OF_MEMORY;
  1227. }
  1228. }
  1229. else
  1230. {
  1231. hr = HRESULT_FROM_WIN32( lRes );
  1232. }
  1233. cName = dwBuffSize;
  1234. }
  1235. delete [] wszName;
  1236. if ( FAILED(hr) )
  1237. {
  1238. ERRORTRACE((LOG_ESS,"Failed enumerating active namespaces. "
  1239. "Treating all namespaces as active. HR=0x%x\n", hr));
  1240. //
  1241. // reset our registry data. We'll rediscover it again.
  1242. //
  1243. RegDeleteSubKeysW( hkeyEss );
  1244. //
  1245. // Also need to reset request object to clear any requests
  1246. // that were added on this enumeration.
  1247. //
  1248. pReq->Reset();
  1249. }
  1250. }
  1251. else
  1252. {
  1253. //
  1254. // reset our registry data. We'll rediscover it again.
  1255. //
  1256. RegDeleteSubKeysW( hkeyEss );
  1257. hr = WBEM_S_FALSE;
  1258. }
  1259. RegCloseKey( hkeyEss );
  1260. }
  1261. else
  1262. {
  1263. hr = HRESULT_FROM_WIN32( lRes );
  1264. }
  1265. //
  1266. // If there was any problem or we just created the key for the
  1267. // first time or we are simply told to rediscover, then we have to recurse
  1268. // namespaces and discover.
  1269. //
  1270. if ( hr != WBEM_S_NO_ERROR || dwDisp != REG_OPENED_EXISTING_KEY )
  1271. {
  1272. DEBUGTRACE((LOG_ESS,"ESS Treating all namespaces as active during "
  1273. "Initialize\n"));
  1274. //
  1275. // recurse namespaces from root
  1276. //
  1277. RecursivePrepareNamespaceInitRequests( L"root", pRoot, pReq );
  1278. }
  1279. if ( aRequests.Add( pReq ) < 0 )
  1280. {
  1281. delete pReq;
  1282. return WBEM_E_OUT_OF_MEMORY;
  1283. }
  1284. return WBEM_S_NO_ERROR;
  1285. }
  1286. //
  1287. // This method schedules all active namespaces for initialization.
  1288. //
  1289. HRESULT CEss::LoadActiveNamespaces( IWbemServices* pRoot, BOOL bRediscover )
  1290. {
  1291. HRESULT hr;
  1292. InitActiveNsRequestList aRequests;
  1293. hr = PrepareNamespaceInitRequests( pRoot, bRediscover, aRequests );
  1294. if ( FAILED(hr) )
  1295. {
  1296. return hr;
  1297. }
  1298. //
  1299. // hold an active namespace init count while we schedule requests.
  1300. // this will keep ess from transitioning to ready until it has
  1301. // scheduled all requests.
  1302. //
  1303. m_lOutstandingActiveNamespaceInit = 1;
  1304. for( int i=0; i < aRequests.GetSize(); i++ )
  1305. {
  1306. int cNamespaces = aRequests[i]->GetNumNamespaces();
  1307. if ( cNamespaces > 0 )
  1308. {
  1309. InterlockedExchangeAdd( &m_lOutstandingActiveNamespaceInit,
  1310. cNamespaces );
  1311. }
  1312. hr = ScheduleNamespaceInitialize( aRequests[i] );
  1313. if ( FAILED(hr) )
  1314. {
  1315. InterlockedExchangeAdd( &m_lOutstandingActiveNamespaceInit,
  1316. 0-cNamespaces );
  1317. delete aRequests[i];
  1318. }
  1319. }
  1320. NotifyActiveNamespaceInitComplete();
  1321. if (bRediscover)
  1322. {
  1323. CPersistentConfig cfg;
  1324. cfg.SetPersistentCfgValue(PERSIST_CFGVAL_CORE_ESS_TO_BE_INITIALIZED,0);
  1325. }
  1326. return WBEM_S_NO_ERROR;
  1327. }
  1328. //
  1329. // This method schedules a namespace init request. It handles deferring
  1330. // initialization if the machine is currently booting. If the request
  1331. // is known to only initialize inactive namespaces, then we do not defer
  1332. // initialization even in the boot phase. This is so we don't cause events
  1333. // in inactive namespaces to be queued up while we're waiting for the deferred
  1334. // initialization to complete.
  1335. //
  1336. HRESULT CEss::ScheduleNamespaceInitialize( CExecRequest* pRequest )
  1337. {
  1338. DWORD dwTickCount = GetTickCount();
  1339. if ( dwTickCount >= BOOT_PHASE_MS )
  1340. {
  1341. HRESULT hres = Enqueue(pRequest);
  1342. if( FAILED(hres) )
  1343. {
  1344. return hres;
  1345. }
  1346. return WBEM_S_NO_ERROR;
  1347. }
  1348. if ( m_hExitBootPhaseTimer == NULL )
  1349. {
  1350. //
  1351. // cause a timer to be fired that will activate the thread queue
  1352. // after we're out of the boot phase.
  1353. //
  1354. if ( !CreateTimerQueueTimer( &m_hExitBootPhaseTimer,
  1355. NULL,
  1356. ExitBootPhaseCallback,
  1357. this,
  1358. BOOT_PHASE_MS-dwTickCount,
  1359. 0,
  1360. WT_EXECUTEINTIMERTHREAD ) )
  1361. {
  1362. return HRESULT_FROM_WIN32( GetLastError() );
  1363. }
  1364. }
  1365. if ( m_aDeferredNSInitRequests.Add( pRequest ) < 0 )
  1366. {
  1367. return WBEM_E_OUT_OF_MEMORY;
  1368. }
  1369. return WBEM_S_FALSE;
  1370. }
  1371. void CALLBACK CEss::ExitBootPhaseCallback( LPVOID pvThis, BOOLEAN )
  1372. {
  1373. DEBUGTRACE((LOG_ESS, "Exiting Boot Phase.\n" ));
  1374. ((CEss*)pvThis)->ExecuteDeferredNSInitRequests();
  1375. }
  1376. void CEss::ExecuteDeferredNSInitRequests()
  1377. {
  1378. HRESULT hr;
  1379. CInCritSec ics( &m_cs );
  1380. for( int i=0; i < m_aDeferredNSInitRequests.GetSize(); i++ )
  1381. {
  1382. hr = Enqueue( m_aDeferredNSInitRequests[i] );
  1383. if ( FAILED(hr) )
  1384. {
  1385. ERRORTRACE((LOG_ESS, "Critical Error. Could not enqueue "
  1386. "deferred namespace init requests\n"));
  1387. delete m_aDeferredNSInitRequests[i];
  1388. }
  1389. }
  1390. m_aDeferredNSInitRequests.RemoveAll();
  1391. }
  1392. void CEss::TriggerDeferredInitialization()
  1393. {
  1394. if ( GetTickCount() >= BOOT_PHASE_MS )
  1395. {
  1396. //
  1397. // avoid calling execute() if possible since it grabs an ess wide cs.
  1398. //
  1399. return;
  1400. }
  1401. DEBUGTRACE((LOG_ESS, "Triggering ESS Namespace Requests "
  1402. "during Boot phase\n" ));
  1403. ExecuteDeferredNSInitRequests();
  1404. }
  1405. HRESULT CEss::GetNamespacePointer( LPCWSTR wszNamespace,
  1406. BOOL bRepositoryOnly,
  1407. RELEASE_ME IWbemServices** ppNamespace )
  1408. {
  1409. HRESULT hres;
  1410. if( m_pLocator == NULL )
  1411. {
  1412. if( m_pCoreServices != NULL )
  1413. {
  1414. long lFlags = WMICORE_CLIENT_TYPE_ESS;
  1415. if ( bRepositoryOnly )
  1416. {
  1417. lFlags |= WMICORE_FLAG_REPOSITORY;
  1418. }
  1419. hres = m_pCoreServices->GetServices( wszNamespace, NULL,NULL,
  1420. lFlags,
  1421. IID_IWbemServices,
  1422. (void**)ppNamespace );
  1423. }
  1424. else
  1425. {
  1426. hres = WBEM_E_CRITICAL_ERROR;
  1427. }
  1428. }
  1429. else
  1430. {
  1431. BSTR strNamespace = SysAllocString(wszNamespace);
  1432. if ( NULL == strNamespace )
  1433. {
  1434. return WBEM_E_OUT_OF_MEMORY;
  1435. }
  1436. hres = m_pLocator->ConnectServer( strNamespace, NULL, NULL, 0, 0, NULL,
  1437. NULL, ppNamespace);
  1438. SysFreeString(strNamespace);
  1439. if ( SUCCEEDED(hres) )
  1440. {
  1441. hres = WBEM_S_FALSE;
  1442. }
  1443. }
  1444. return hres;
  1445. }
  1446. HRESULT CEss::ReloadProvider( long lFlags,
  1447. LPCWSTR wszNamespace,
  1448. LPCWSTR wszProvider )
  1449. {
  1450. HRESULT hr;
  1451. try
  1452. {
  1453. CInObjectCount ioc(this);
  1454. CWbemPtr<CEssNamespace> pNamespace;
  1455. hr = GetNamespaceObject( wszNamespace, FALSE, &pNamespace);
  1456. if ( SUCCEEDED(hr) )
  1457. {
  1458. DEBUGTRACE((LOG_ESS,"Reloading Provider %S in namespace %S at "
  1459. "request of external subsystem\n ",
  1460. wszProvider, wszNamespace ));
  1461. hr = pNamespace->ReloadProvider( lFlags, wszProvider );
  1462. }
  1463. }
  1464. catch( CX_MemoryException )
  1465. {
  1466. hr = WBEM_E_OUT_OF_MEMORY;
  1467. }
  1468. return hr;
  1469. }
  1470. //******************************************************************************
  1471. // public
  1472. //
  1473. // See ess.h for documentation
  1474. //
  1475. //******************************************************************************
  1476. HRESULT CEss::ProcessEvent(READ_ONLY CEventRepresentation& Event, long lFlags)
  1477. {
  1478. HRESULT hres;
  1479. try
  1480. {
  1481. CInObjectCount ioc(this);
  1482. // Find the right namespace object
  1483. // ===============================
  1484. CEssNamespace* pNamespace = NULL;
  1485. hres = GetNamespaceObject(Event.wsz1, FALSE, &pNamespace);
  1486. if(FAILED(hres))
  1487. return hres;
  1488. CTemplateReleaseMe<CEssNamespace> rm1(pNamespace);
  1489. // Get it to process the event
  1490. // ===========================
  1491. return pNamespace->ProcessEvent(Event, lFlags);
  1492. }
  1493. catch(...)
  1494. {
  1495. throw;
  1496. return WBEM_E_OUT_OF_MEMORY;
  1497. }
  1498. }
  1499. HRESULT CEss::ProcessQueryObjectSinkEvent( READ_ONLY CEventRepresentation& Event )
  1500. {
  1501. HRESULT hres;
  1502. try
  1503. {
  1504. CInObjectCount ioc(this);
  1505. //
  1506. // Find the right namespace object
  1507. //
  1508. CEssNamespace* pNamespace = NULL;
  1509. hres = GetNamespaceObject(Event.wsz1, FALSE, &pNamespace);
  1510. if( FAILED( hres ) )
  1511. {
  1512. return hres;
  1513. }
  1514. CTemplateReleaseMe<CEssNamespace> rm1(pNamespace);
  1515. //
  1516. // Get it to process the event
  1517. //
  1518. return pNamespace->ProcessQueryObjectSinkEvent( Event );
  1519. }
  1520. catch(...)
  1521. {
  1522. throw;
  1523. return WBEM_E_OUT_OF_MEMORY;
  1524. }
  1525. }
  1526. HRESULT CEss::VerifyInternalEvent(READ_ONLY CEventRepresentation& Event)
  1527. {
  1528. HRESULT hres;
  1529. try
  1530. {
  1531. CInObjectCount ioc(this);
  1532. // Find the right namespace object
  1533. // ===============================
  1534. CEssNamespace* pNamespace = NULL;
  1535. hres = GetNamespaceObject(Event.wsz1, FALSE, &pNamespace);
  1536. if(FAILED(hres))
  1537. return hres;
  1538. CTemplateReleaseMe<CEssNamespace> rm1(pNamespace);
  1539. // Get it to process the event
  1540. // ===========================
  1541. return pNamespace->ValidateSystemEvent(Event);
  1542. }
  1543. catch(...)
  1544. {
  1545. throw;
  1546. return WBEM_E_OUT_OF_MEMORY;
  1547. }
  1548. }
  1549. HRESULT CEss::RegisterNotificationSink( WBEM_CWSTR wszNamespace,
  1550. WBEM_CWSTR wszQueryLanguage,
  1551. WBEM_CWSTR wszQuery,
  1552. long lFlags,
  1553. IWbemContext* pContext,
  1554. IWbemObjectSink* pSink )
  1555. {
  1556. HRESULT hres;
  1557. try
  1558. {
  1559. if(wbem_wcsicmp(wszQueryLanguage, L"WQL"))
  1560. return WBEM_E_INVALID_QUERY_TYPE;
  1561. CInObjectCount ioc(this);
  1562. // Find the right namespace object
  1563. // ===============================
  1564. CEssNamespace* pNamespace = NULL;
  1565. hres = GetNamespaceObject(wszNamespace, FALSE, &pNamespace);
  1566. if(FAILED(hres))
  1567. return hres;
  1568. CTemplateReleaseMe<CEssNamespace> rm1(pNamespace);
  1569. // Get the object to do it
  1570. // =======================
  1571. HRESULT hr;
  1572. hr = pNamespace->RegisterNotificationSink( wszQueryLanguage,
  1573. wszQuery,
  1574. lFlags,
  1575. WMIMSG_FLAG_QOS_EXPRESS,
  1576. pContext,
  1577. pSink );
  1578. return hr;
  1579. }
  1580. catch(...)
  1581. {
  1582. throw;
  1583. return WBEM_E_OUT_OF_MEMORY;
  1584. }
  1585. }
  1586. HRESULT CEss::RemoveNotificationSink(IWbemObjectSink* pSink)
  1587. {
  1588. HRESULT hres;
  1589. try
  1590. {
  1591. CInObjectCount ioc(this);
  1592. // Create a list of AddRefed namespace objects that we can use
  1593. // ===========================================================
  1594. CRefedPointerArray<CEssNamespace> apNamespaces;
  1595. {
  1596. CInCritSec ics(&m_cs);
  1597. for(TNamespaceIterator it = m_mapNamespaces.begin();
  1598. it != m_mapNamespaces.end();
  1599. it++)
  1600. {
  1601. if(apNamespaces.Add(it->second) < 0)
  1602. return WBEM_E_OUT_OF_MEMORY;
  1603. }
  1604. }
  1605. // Get all of them to remove this sink
  1606. // ===================================
  1607. HRESULT hresGlobal = WBEM_E_NOT_FOUND;
  1608. for(int i = 0; i < apNamespaces.GetSize(); i++)
  1609. {
  1610. hres = apNamespaces[i]->RemoveNotificationSink(pSink);
  1611. if(FAILED(hres))
  1612. {
  1613. if(hres != WBEM_E_NOT_FOUND)
  1614. {
  1615. // Actual error --- take note
  1616. // ==========================
  1617. hresGlobal = hres;
  1618. }
  1619. }
  1620. else
  1621. {
  1622. // Found some
  1623. // ==========
  1624. if(hresGlobal == WBEM_E_NOT_FOUND)
  1625. hresGlobal = WBEM_S_NO_ERROR;
  1626. }
  1627. }
  1628. return hresGlobal;
  1629. }
  1630. catch(...)
  1631. {
  1632. throw;
  1633. return WBEM_E_OUT_OF_MEMORY;
  1634. }
  1635. }
  1636. HRESULT CEss::PurgeNamespace(LPCWSTR wszNamespace)
  1637. {
  1638. LPWSTR wszNormName = NormalizeNamespaceString( wszNamespace );
  1639. if ( wszNormName == NULL )
  1640. {
  1641. return WBEM_E_OUT_OF_MEMORY;
  1642. }
  1643. CVectorDeleteMe<WCHAR> dmwszNormName( wszNormName );
  1644. CEssNamespace* pNamespace = NULL;
  1645. {
  1646. CInCritSec ics(&m_cs);
  1647. // Purge it from the timer generator
  1648. // =================================
  1649. m_TimerGenerator.Remove(wszNormName);
  1650. // Find it in the map
  1651. // ==================
  1652. TNamespaceIterator it;
  1653. try
  1654. {
  1655. it = m_mapNamespaces.find(wszNormName);
  1656. }
  1657. catch (CX_MemoryException &)
  1658. {
  1659. return WBEM_E_OUT_OF_MEMORY;
  1660. };
  1661. if(it == m_mapNamespaces.end())
  1662. return WBEM_S_FALSE;
  1663. // Keep it for later
  1664. // =================
  1665. pNamespace = it->second;
  1666. // Remove it from the map
  1667. // ======================
  1668. m_mapNamespaces.erase(it);
  1669. }
  1670. // Wait for initialization to complete
  1671. // ===================================
  1672. pNamespace->Shutdown();
  1673. pNamespace->Release();
  1674. return WBEM_S_NO_ERROR;
  1675. }
  1676. HRESULT CEss::DecorateObject(IWbemClassObject* pObj, LPCWSTR wszNamespace)
  1677. {
  1678. return CEventRepresentation::mstatic_pDecorator->DecorateObject(pObj,
  1679. (LPWSTR)wszNamespace);
  1680. }
  1681. HRESULT CEss::AddSleepCharge(DWORD dwSleep)
  1682. {
  1683. if(dwSleep)
  1684. Sleep(dwSleep);
  1685. return S_OK;
  1686. }
  1687. HRESULT CEss::AddCache()
  1688. {
  1689. return m_LimitControl.AddMember();
  1690. }
  1691. HRESULT CEss::RemoveCache()
  1692. {
  1693. return m_LimitControl.RemoveMember();
  1694. }
  1695. HRESULT CEss::AddToCache(DWORD dwAdd, DWORD dwMemberTotal, DWORD* pdwSleep)
  1696. {
  1697. DWORD dwSleep;
  1698. HRESULT hres = m_LimitControl.Add(dwAdd, dwMemberTotal, &dwSleep);
  1699. if(SUCCEEDED(hres))
  1700. {
  1701. if(pdwSleep)
  1702. *pdwSleep = dwSleep;
  1703. else
  1704. AddSleepCharge(dwSleep);
  1705. }
  1706. return hres;
  1707. }
  1708. HRESULT CEss::RemoveFromCache(DWORD dwRemove)
  1709. {
  1710. return m_LimitControl.Remove(dwRemove);
  1711. }
  1712. void CEss::IncrementObjectCount()
  1713. {
  1714. InterlockedIncrement(&m_lObjectCount);
  1715. }
  1716. void CEss::DecrementObjectCount()
  1717. {
  1718. if(InterlockedDecrement(&m_lObjectCount) == 0)
  1719. {
  1720. // No need to purge the cache --- David knows I am ready to unload
  1721. }
  1722. }
  1723. HRESULT CEss::InitializeTimerGenerator(LPCWSTR wszNamespace,
  1724. IWbemServices* pNamespace)
  1725. {
  1726. return GetTimerGenerator().LoadTimerEventQueue(wszNamespace, pNamespace);
  1727. }
  1728. HRESULT CEss::EnqueueDeliver(CQueueingEventSink* pDest)
  1729. {
  1730. return m_Queue.EnqueueDeliver(pDest);
  1731. }
  1732. HRESULT CEss::Enqueue(CExecRequest* pReq)
  1733. {
  1734. return m_Queue.Enqueue(pReq);
  1735. }
  1736. HRESULT CEss::GetToken(PSID pSid, IWbemToken** ppToken)
  1737. {
  1738. return m_pTokenCache->GetToken((BYTE*)pSid, ppToken);
  1739. }
  1740. void CEss::DumpStatistics(FILE* f, long lFlags)
  1741. {
  1742. CInCritSec ics(&m_cs);
  1743. time_t t;
  1744. time(&t);
  1745. struct tm* ptm = localtime(&t);
  1746. fprintf(f, "Statistics at %s", asctime(ptm));
  1747. time(&t);
  1748. ptm = localtime(&t);
  1749. fprintf(f, "Commence at %s", asctime(ptm));
  1750. for(TNamespaceIterator it = m_mapNamespaces.begin();
  1751. it != m_mapNamespaces.end(); it++)
  1752. {
  1753. it->second->DumpStatistics(f, lFlags);
  1754. }
  1755. time(&t);
  1756. ptm = localtime(&t);
  1757. fprintf(f, "Done at %s\n", asctime(ptm));
  1758. }
  1759. HRESULT CEss::GetProviderFactory( LPCWSTR wszNamespaceName,
  1760. IWbemServices* pNamespace,
  1761. RELEASE_ME _IWmiProviderFactory** ppFactory )
  1762. {
  1763. HRESULT hres;
  1764. *ppFactory = NULL;
  1765. if ( m_pProvSS == NULL )
  1766. {
  1767. ERRORTRACE((LOG_ESS, "Trying to get Provider Factory, but "
  1768. "No provider subsystem!!\n"));
  1769. return WBEM_E_CRITICAL_ERROR;
  1770. }
  1771. //
  1772. // Get IWbemServicesEx, just for Steve
  1773. //
  1774. IWbemServices* pEx;
  1775. hres = pNamespace->QueryInterface(IID_IWbemServices, (void**)&pEx);
  1776. if(FAILED(hres))
  1777. {
  1778. ERRORTRACE((LOG_ESS, "No Ex interface: 0x%X\n", hres));
  1779. return hres;
  1780. }
  1781. CReleaseMe rm1(pEx);
  1782. //
  1783. // Get Provider factory
  1784. //
  1785. hres = m_pProvSS->Create( pEx,
  1786. 0,
  1787. GetCurrentEssContext(),
  1788. wszNamespaceName,
  1789. IID__IWmiProviderFactory,
  1790. (void**)ppFactory );
  1791. if(FAILED(hres))
  1792. {
  1793. ERRORTRACE((LOG_ESS, "No provider factory: 0x%X\n", hres));
  1794. }
  1795. return hres;
  1796. }