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.

1870 lines
42 KiB

  1. //***************************************************************************
  2. //
  3. // SceProv.CPP
  4. //
  5. // Module: SCE WMI provider code
  6. //
  7. // Purpose: Defines the CSceWmiProv class. An object of this class is
  8. // created by the class factory for each connection.
  9. //
  10. // Copyright (c) 1000-2001 Microsoft Corporation
  11. //
  12. //***************************************************************************
  13. #include "sceprov.h"
  14. #include "requestobject.h"
  15. #include <process.h>
  16. #include <Userenv.h>
  17. #include "genericclass.h"
  18. #include "Tranx.h"
  19. #include "operation.h"
  20. //
  21. // instantiate out unique static member
  22. //
  23. CHeap_Exception CSceWmiProv::m_he(CHeap_Exception::E_ALLOCATION_ERROR);
  24. LPCWSTR pszDefLogFilePath = L"\\Local Settings\\SceWMILog\\MethodLog.txt";
  25. CComBSTR g_bstrDefLogFilePath;
  26. //
  27. // definition of our global variables
  28. //
  29. CCriticalSection g_CS;
  30. CLogOptions g_LogOption;
  31. CComBSTR g_bstrTranxID;
  32. CCriticalSection CSceOperation::s_OperationCS;
  33. /*
  34. Routine Description:
  35. Name:
  36. CCriticalSection::CCriticalSection
  37. Functionality:
  38. Constructor. Initializing the critical section
  39. Virtual:
  40. No.
  41. Arguments:
  42. None.
  43. Return Value:
  44. None as any constructor
  45. Notes:
  46. if you create any local members, think about initialize them here
  47. */
  48. CCriticalSection::CCriticalSection ()
  49. {
  50. ::InitializeCriticalSection(&m_cs);
  51. }
  52. /*
  53. Routine Description:
  54. Name:
  55. CCriticalSection::~CCriticalSection
  56. Functionality:
  57. Destructor. Deleting the critical section.
  58. Virtual:
  59. No.
  60. Arguments:
  61. None.
  62. Return Value:
  63. None as any destructor.
  64. Notes:
  65. if you create any local members, think about initialize them here
  66. */
  67. CCriticalSection::~CCriticalSection()
  68. {
  69. ::DeleteCriticalSection(&m_cs);
  70. }
  71. /*
  72. Routine Description:
  73. Name:
  74. CCriticalSection::Enter
  75. Functionality:
  76. Equivalent of EnterCriticalSection
  77. Virtual:
  78. No.
  79. Arguments:
  80. None.
  81. Return Value:
  82. None.
  83. Notes:
  84. */
  85. void CCriticalSection::Enter()
  86. {
  87. ::EnterCriticalSection(&m_cs);
  88. }
  89. /*
  90. Routine Description:
  91. Name:
  92. CCriticalSection::Leave
  93. Functionality:
  94. Equivalent of LeaveCriticalSection
  95. Virtual:
  96. No.
  97. Arguments:
  98. None.
  99. Return Value:
  100. None.
  101. Notes:
  102. */
  103. void CCriticalSection::Leave()
  104. {
  105. ::LeaveCriticalSection(&m_cs);
  106. }
  107. //
  108. // implementing CLogOptions
  109. //
  110. /*
  111. Routine Description:
  112. Name:
  113. CLogOptions::GetLogOptionsFromWbemObject
  114. Functionality:
  115. Query the unique WMI object for SCE logging options and update the class members.
  116. Virtual:
  117. No.
  118. Arguments:
  119. None.
  120. Return Value:
  121. None.
  122. Notes:
  123. log options is determined by our WMI class called Sce_LogOptions.
  124. a unique instance is deposited in WMI depository for controlling log options.
  125. This function will query for this instance and thus update the log options
  126. in case it has been modified.
  127. */
  128. void CLogOptions::GetLogOptionsFromWbemObject (
  129. IN IWbemServices* pNamespace
  130. )
  131. {
  132. //
  133. // we can't update the log options without a namespace. In case of any failure
  134. // to reach the instance, we leave our default option (which is to log error only
  135. // non-verbose)
  136. //
  137. if (pNamespace != NULL)
  138. {
  139. CComPtr<IWbemClassObject> srpLogStatus;
  140. HRESULT hr = pNamespace->GetObject(SCEWMI_LOGOPTIONS_CLASS, 0, NULL, &srpLogStatus, NULL);
  141. if (SUCCEEDED(hr))
  142. {
  143. CComVariant varErrorType, varVerbose;
  144. //
  145. // m_dwOption is a bit pattern recording the error logging options
  146. // (inside SCE_LOG_Error_Mask) and verbose logging options (inside SCE_LOG_Verbose_Mask)
  147. //
  148. //
  149. // preserve the verbose portion of the option (SCE_LOG_Verbose_Mask), but
  150. // update the error portion of the option (SCE_LOG_Error_Mask)
  151. //
  152. if (SUCCEEDED(srpLogStatus->Get(pLogErrorType, 0, &varErrorType, NULL, NULL)))
  153. {
  154. m_dwOption = (m_dwOption & SCE_LOG_Verbose_Mask) | (SCE_LOG_Error_Mask & varErrorType.iVal);
  155. }
  156. //
  157. // Verbose is a boolean property. Set/unset the bit depending on the boolean value
  158. //
  159. if (SUCCEEDED(srpLogStatus->Get(pLogVerbose, 0, &varVerbose, NULL, NULL)))
  160. {
  161. if (varVerbose.vt == VT_BOOL && varVerbose.boolVal == VARIANT_TRUE)
  162. {
  163. m_dwOption = Sce_log_Verbose | m_dwOption;
  164. }
  165. else
  166. {
  167. m_dwOption &= ~Sce_log_Verbose;
  168. }
  169. }
  170. }
  171. }
  172. }
  173. //===========================================================================
  174. // CForeignClassInfo implementations
  175. //===========================================================================
  176. /*
  177. Routine Description:
  178. Name:
  179. CForeignClassInfo::~CForeignClassInfo
  180. Functionality:
  181. Destructor. Cleanup.
  182. Virtual:
  183. No.
  184. Arguments:
  185. None.
  186. Return Value:
  187. None as any destructor
  188. Notes:
  189. if you create any more local members, think about initialize them in
  190. constructor and clean them up in CleanNames or here.
  191. */
  192. CForeignClassInfo::~CForeignClassInfo()
  193. {
  194. ::SysFreeString(bstrNamespace);
  195. ::SysFreeString(bstrClassName);
  196. CleanNames();
  197. }
  198. /*
  199. Routine Description:
  200. Name:
  201. CForeignClassInfo::CleanNames
  202. Functionality:
  203. Cleanup the names vector.
  204. Virtual:
  205. No.
  206. Arguments:
  207. None.
  208. Return Value:
  209. None as any destructor
  210. Notes:
  211. if you create any more local members, think about initialize them in
  212. constructor and clean them up in CleanNames or here.
  213. */
  214. void CForeignClassInfo::CleanNames ()
  215. {
  216. if (m_pVecKeyPropNames)
  217. {
  218. for (int i = 0; i < m_pVecKeyPropNames->size(); i++)
  219. {
  220. ::SysFreeString((*m_pVecKeyPropNames)[i]);
  221. }
  222. delete m_pVecKeyPropNames;
  223. //
  224. // since this is not a destructor, better reset the variable.
  225. //
  226. m_pVecKeyPropNames = NULL;
  227. }
  228. }
  229. //===========================================================================
  230. // Implementing CSceWmiProv
  231. //===========================================================================
  232. /*
  233. Routine Description:
  234. Name:
  235. CSceWmiProv::Initialize
  236. Functionality:
  237. Implementating IWbemProviderInit. Initialize the provider as instrcuted by WMI infrastructure.
  238. Virtual:
  239. Yes.
  240. Arguments:
  241. pszUser - User.
  242. lFlags - not used.
  243. pszNamespace - Namespace string.
  244. pszLocale - Locale string.
  245. pNamespace - COM interface pointer to our namespace.
  246. pCtx - COM interface pointer that was passed around for WMI APIs.
  247. pInitSink - COM interface pointer to notify WMI of results.
  248. Return Value:
  249. Success: WBEM_NO_ERROR.
  250. Failure: Various error code. It is either caused by Impersonation failure or
  251. failure to create default log file directory.
  252. Notes:
  253. You should never call this directly. It's intended for WMI calls.
  254. */
  255. STDMETHODIMP
  256. CSceWmiProv::Initialize (
  257. IN LPWSTR pszUser,
  258. IN LONG lFlags,
  259. IN LPWSTR pszNamespace,
  260. IN LPWSTR pszLocale,
  261. IN IWbemServices * pNamespace,
  262. IN IWbemContext * pCtx,
  263. IN IWbemProviderInitSink * pInitSink
  264. )
  265. {
  266. HRESULT hres = WBEM_NO_ERROR;
  267. //
  268. // make sure that we have a fall back default log file
  269. //
  270. hres = CheckImpersonationLevel();
  271. if (SUCCEEDED(hres))
  272. {
  273. //
  274. // going to modify global data, need thread safety
  275. //
  276. g_CS.Enter();
  277. if (pNamespace)
  278. {
  279. m_srpNamespace = pNamespace;
  280. }
  281. g_bstrDefLogFilePath.Empty();
  282. hres = ::CreateDefLogFile(&g_bstrDefLogFilePath);
  283. g_CS.Leave();
  284. }
  285. //
  286. // Let CIMOM know you are initialized
  287. //
  288. pInitSink->SetStatus(WBEM_S_INITIALIZED, 0);
  289. return hres;
  290. }
  291. /*
  292. Routine Description:
  293. Name:
  294. CSceWmiProv::CreateInstanceEnumAsync
  295. Functionality:
  296. Asynchronously enumerates the instances.
  297. Virtual:
  298. Yes.
  299. Arguments:
  300. strClass - class name that is to be enumerated.
  301. lFlags - not used.
  302. pCtx - COM interface pointer that was passed around for WMI APIs.
  303. pSink - COM interface pointer to notify WMI of results.
  304. Return Value:
  305. Success: Various success code. No guarantee to return WBEM_NO_ERROR.
  306. Failure: Various error code. It is either caused by Impersonation failure or
  307. failure to enumerate the instances.
  308. Notes:
  309. You should never call this directly. It's intended for WMI calls.
  310. */
  311. STDMETHODIMP
  312. CSceWmiProv::CreateInstanceEnumAsync (
  313. const BSTR strClass,
  314. long lFlags,
  315. IWbemContext * pCtx,
  316. IWbemObjectSink * pSink
  317. )
  318. {
  319. if(strClass == NULL || pSink == NULL || m_srpNamespace == NULL)
  320. {
  321. //
  322. // inform WMI that action is complete with errors (WBEM_E_INVALID_PARAMETER)
  323. //
  324. pSink->SetStatus(WBEM_STATUS_COMPLETE, WBEM_E_INVALID_PARAMETER, NULL, NULL);
  325. return WBEM_E_INVALID_PARAMETER;
  326. }
  327. HRESULT hr = WBEM_NO_ERROR;
  328. // our classes are following COM rule so that they won't throw. The following try-catch
  329. // is to guard against critical errors inside our code so that it won't crash the host process
  330. try
  331. {
  332. //
  333. // always impersonated
  334. //
  335. hr = CheckImpersonationLevel();
  336. if ( SUCCEEDED(hr) )
  337. {
  338. //
  339. // We take care of Sce_TransactionToken directly because that is managed by our global variable
  340. //
  341. if (_wcsicmp(strClass, SCEWMI_TRANSACTION_TOKEN_CLASS) == 0)
  342. {
  343. //
  344. // protecting global from multi threads access
  345. //
  346. g_CS.Enter();
  347. LPCWSTR pszTranxID = (LPCWSTR)g_bstrTranxID;
  348. if (NULL == pszTranxID || L'\0' == *pszTranxID)
  349. {
  350. hr = WBEM_E_NOT_FOUND;
  351. }
  352. else
  353. {
  354. hr = CTranxID::SpawnTokenInstance(m_srpNamespace, pszTranxID, pCtx, pSink);
  355. }
  356. g_CS.Leave();
  357. }
  358. else
  359. {
  360. //
  361. // everything else goes through CRequestObject
  362. //
  363. CRequestObject ReqObj(m_srpNamespace);
  364. hr = ReqObj.CreateObject(strClass, pSink, pCtx, ACTIONTYPE_ENUM);
  365. }
  366. }
  367. //
  368. // inform WMI that action is complete with hr as result
  369. //
  370. pSink->SetStatus(WBEM_STATUS_COMPLETE, hr, NULL, NULL);
  371. }
  372. catch(...)
  373. {
  374. hr = WBEM_E_CRITICAL_ERROR;
  375. //
  376. // inform WMI that action is complete with error (WBEM_E_CRITICAL_ERROR)
  377. //
  378. pSink->SetStatus(WBEM_STATUS_COMPLETE, hr, NULL, NULL);
  379. }
  380. return hr;
  381. }
  382. /*
  383. Routine Description:
  384. Name:
  385. CSceWmiProv::CreateInstanceEnumAsync
  386. Functionality:
  387. WMI is asking for a unique single instance (not querying). This function uses
  388. CRequestObject to fulfill the request.
  389. Virtual:
  390. Yes.
  391. Arguments:
  392. strObjectPath - object's path.
  393. lFlags - not used.
  394. pCtx - COM interface pointer that was passed around for WMI APIs.
  395. pSink - COM interface pointer to notify WMI of results (in this case
  396. it is used to notify WMI of the created object.
  397. Return Value:
  398. Success: Various success code. No guarantee to return WBEM_NO_ERROR.
  399. Failure: Various error code. It is either caused by Impersonation failure or
  400. failure to get the instances.
  401. Notes:
  402. You should never call this directly. It's intended for WMI calls.
  403. */
  404. STDMETHODIMP
  405. CSceWmiProv::GetObjectAsync (
  406. IN const BSTR strObjectPath,
  407. IN long lFlags,
  408. IN IWbemContext * pCtx,
  409. IN IWbemObjectSink * pSink
  410. )
  411. {
  412. //
  413. //check parameters
  414. //
  415. if(strObjectPath == NULL || pSink == NULL || m_srpNamespace == NULL)
  416. {
  417. //
  418. // inform WMI that action is complete with WBEM_E_INVALID_PARAMETER as error result
  419. //
  420. pSink->SetStatus(WBEM_STATUS_COMPLETE, WBEM_E_INVALID_PARAMETER, NULL, NULL);
  421. return WBEM_E_INVALID_PARAMETER;
  422. }
  423. HRESULT hr = WBEM_NO_ERROR;
  424. //
  425. // our classes are following COM rule so that they won't throw. The following try-catch
  426. // is to guard against critical errors inside our code so that it won't crash the host process
  427. //
  428. try
  429. {
  430. //
  431. // make sure impersonated
  432. //
  433. hr = CheckImpersonationLevel();
  434. if ( SUCCEEDED(hr) )
  435. {
  436. CRequestObject ReqObj(m_srpNamespace);
  437. //
  438. // Get the requested object. It's a single instance get!
  439. //
  440. hr = ReqObj.CreateObject(strObjectPath, pSink, pCtx, ACTIONTYPE_GET);
  441. //
  442. // if CRequestObject doesn't know how to create the object, it might be Sce_TransactionToken
  443. //
  444. if (FAILED(hr) && wcsstr(strObjectPath, SCEWMI_TRANSACTION_TOKEN_CLASS) != NULL)
  445. {
  446. //
  447. // protecting global memory
  448. //
  449. g_CS.Enter();
  450. //
  451. // whether this Sce_TransactionToken instance exists all depends on the global variable
  452. //
  453. LPCWSTR pszTranxID = (LPCWSTR)g_bstrTranxID;
  454. if (NULL == pszTranxID || L'\0' == *pszTranxID)
  455. {
  456. hr = WBEM_E_NOT_FOUND;
  457. }
  458. else
  459. {
  460. hr = CTranxID::SpawnTokenInstance(m_srpNamespace, pszTranxID, pCtx, pSink);
  461. }
  462. g_CS.Leave();
  463. }
  464. }
  465. //
  466. // inform WMI that action is complete with hr as result
  467. //
  468. pSink->SetStatus(WBEM_STATUS_COMPLETE, hr, NULL, NULL);
  469. }
  470. catch(...)
  471. {
  472. hr = WBEM_E_CRITICAL_ERROR;
  473. //
  474. // inform WMI that action is complete with error (WBEM_E_CRITICAL_ERROR)
  475. //
  476. pSink->SetStatus(WBEM_STATUS_COMPLETE, hr, NULL, NULL);
  477. }
  478. return hr;
  479. }
  480. /*
  481. Routine Description:
  482. Name:
  483. CSceWmiProv::PutInstanceAsync
  484. Functionality:
  485. WMI requests that something has created and put this instance. For all of our
  486. WMI classes, except one, this means to persist the instance information into a store.
  487. Virtual:
  488. Yes.
  489. Arguments:
  490. pInst - COM interface pointer that identifies the WMI object.
  491. lFlags - not used.
  492. pCtx - COM interface pointer that was passed around for WMI APIs.
  493. pSink - COM interface pointer to notify WMI of results (in this case
  494. it is used to notify WMI of the created object.
  495. Return Value:
  496. Success: Various success code. No guarantee to return WBEM_NO_ERROR.
  497. Failure: Various error code. It is either caused by Impersonation failure or
  498. failure to put the instances into our namespace.
  499. Notes:
  500. You should never call this directly. It's intended for WMI calls.
  501. */
  502. STDMETHODIMP CSceWmiProv::PutInstanceAsync (
  503. IN IWbemClassObject FAR * pInst,
  504. IN long lFlags,
  505. IN IWbemContext * pCtx,
  506. IN IWbemObjectSink FAR * pSink
  507. )
  508. {
  509. if(pInst == NULL || pSink == NULL)
  510. {
  511. //
  512. // inform WMI that action is complete with error (WBEM_E_INVALID_PARAMETER)
  513. //
  514. pSink->SetStatus(WBEM_STATUS_COMPLETE, WBEM_E_INVALID_PARAMETER, NULL, NULL);
  515. return WBEM_E_INVALID_PARAMETER;
  516. }
  517. HRESULT hr = WBEM_NO_ERROR;
  518. //
  519. // our classes are following COM rule so that they won't throw. The following try-catch
  520. // is to guard against critical errors inside our code so that it won't crash the host process.
  521. //
  522. try
  523. {
  524. //
  525. // make sure impersonated
  526. //
  527. if (SUCCEEDED(hr = CheckImpersonationLevel()))
  528. {
  529. CRequestObject ReqObj(m_srpNamespace);
  530. //
  531. // Put the object
  532. //
  533. hr = ReqObj.PutObject(pInst, pSink, pCtx);
  534. }
  535. //
  536. // inform WMI that action is complete with hr as result
  537. //
  538. pSink->SetStatus(WBEM_STATUS_COMPLETE, hr , NULL, NULL);
  539. }
  540. catch(...)
  541. {
  542. hr = WBEM_E_CRITICAL_ERROR;
  543. //
  544. // inform WMI that action is complete with error (WBEM_E_CRITICAL_ERROR)
  545. //
  546. pSink->SetStatus(WBEM_STATUS_COMPLETE, hr, NULL, NULL);
  547. }
  548. return hr;
  549. }
  550. /*
  551. Routine Description:
  552. Name:
  553. CSceWmiProv::ExecMethodAsync
  554. Functionality:
  555. Executes a method on an SCE class or instance
  556. Virtual:
  557. Yes.
  558. Arguments:
  559. ObjectPath - the path of the WMI object.
  560. Method - the method.
  561. lFlags - not used.
  562. pCtx - COM interface pointer that was passed around for WMI APIs.
  563. pInParams - COM interface pointer the input parameter object.
  564. pSink - COM interface pointer to notify WMI of results (in this case
  565. it is used to notify WMI of the created object.
  566. Return Value:
  567. Success: Various success code. No guarantee to return WBEM_NO_ERROR.
  568. Failure: Various error code. It is either caused by Impersonation failure or
  569. failure to execute the method.
  570. Notes:
  571. You should never call this directly. It's intended for WMI calls.
  572. */
  573. STDMETHODIMP CSceWmiProv::ExecMethodAsync (
  574. IN const BSTR ObjectPath,
  575. IN const BSTR Method,
  576. IN long lFlags,
  577. IN IWbemContext * pCtx,
  578. IN IWbemClassObject * pInParams,
  579. IN IWbemObjectSink * pSink
  580. )
  581. {
  582. HRESULT hr = WBEM_NO_ERROR;
  583. //
  584. // Do a check of arguments and make sure we have pointer to Namespace
  585. //
  586. if (pSink == NULL)
  587. {
  588. //
  589. // we can't even notify because the sink is null. Not likely to happen unless WMI has some serious problems.
  590. //
  591. return WBEM_E_INVALID_PARAMETER;
  592. }
  593. else if (ObjectPath == NULL || Method == NULL)
  594. {
  595. //
  596. // inform WMI that action is complete with error (WBEM_E_INVALID_PARAMETER
  597. //
  598. pSink->SetStatus(WBEM_STATUS_COMPLETE, WBEM_E_INVALID_PARAMETER, NULL, NULL);
  599. return WBEM_E_INVALID_PARAMETER;
  600. }
  601. //
  602. // is to guard against critical errors inside our code so that it won't crash the host process
  603. //
  604. try
  605. {
  606. //
  607. // make sure impersonated
  608. //
  609. if (SUCCEEDED(hr = CheckImpersonationLevel()))
  610. {
  611. CRequestObject ReqObj(m_srpNamespace);
  612. //
  613. //Execute the method
  614. //
  615. hr = ReqObj.ExecMethod(ObjectPath, Method, pInParams, pSink, pCtx);
  616. }
  617. //
  618. // inform WMI that action is complete with hr as result
  619. //
  620. pSink->SetStatus(WBEM_STATUS_COMPLETE, hr , NULL, NULL);
  621. }
  622. catch(...)
  623. {
  624. hr = WBEM_E_CRITICAL_ERROR;
  625. //
  626. // inform WMI that action is complete with error (WBEM_E_CRITICAL_ERROR)
  627. //
  628. pSink->SetStatus(WBEM_STATUS_COMPLETE, hr, NULL, NULL);
  629. }
  630. return hr;
  631. }
  632. /*
  633. Routine Description:
  634. Name:
  635. CSceWmiProv::DeleteInstanceAsync
  636. Functionality:
  637. Delete the instance identified by the given path.
  638. Virtual:
  639. Yes.
  640. Arguments:
  641. ObjectPath - the path of the WMI object.
  642. lFlags - not used.
  643. pCtx - COM interface pointer that was passed around for WMI APIs.
  644. pInParams - COM interface pointer the input parameter object.
  645. pSink - COM interface pointer to notify WMI of results (in this case
  646. it is used to notify WMI of the created object.
  647. Return Value:
  648. Success: Various success code. No guarantee to return WBEM_NO_ERROR.
  649. Failure: Various error code. It is either caused by Impersonation failure or
  650. failure to delete the instance.
  651. Notes:
  652. You should never call this directly. It's intended for WMI calls.
  653. */
  654. STDMETHODIMP CSceWmiProv::DeleteInstanceAsync (
  655. IN const BSTR ObjectPath,
  656. IN long lFlags,
  657. IN IWbemContext * pCtx,
  658. IN IWbemObjectSink * pSink
  659. )
  660. {
  661. if (pSink == NULL)
  662. {
  663. //
  664. // we can't even notify because the sink is null. Not likely to happen unless WMI has some serious problems.
  665. //
  666. return WBEM_E_INVALID_PARAMETER;
  667. }
  668. else if (ObjectPath == NULL)
  669. {
  670. //
  671. // inform WMI that action is complete with error (WBEM_E_INVALID_PARAMETER)
  672. //
  673. pSink->SetStatus(WBEM_STATUS_COMPLETE, WBEM_E_INVALID_PARAMETER, NULL, NULL);
  674. return WBEM_E_INVALID_PARAMETER;
  675. }
  676. HRESULT hr = WBEM_NO_ERROR;
  677. //
  678. // our classes are following COM rule so that they won't throw. The following try-catch
  679. // is to guard against critical errors inside our code so that it won't crash the host process
  680. //
  681. try
  682. {
  683. //
  684. // make sure impersonated
  685. //
  686. if (SUCCEEDED(hr = CheckImpersonationLevel()))
  687. {
  688. CRequestObject ReqObj(m_srpNamespace);
  689. hr = ReqObj.DeleteObject(ObjectPath, pSink, pCtx);
  690. }
  691. #ifdef _PRIVATE_DEBUG
  692. if(!HeapValidate(GetProcessHeap(),NULL , NULL)) DebugBreak();
  693. #endif
  694. //
  695. // inform WMI that action is complete with hr as result
  696. //
  697. pSink->SetStatus(WBEM_STATUS_COMPLETE ,hr , NULL, NULL);
  698. }
  699. catch(...)
  700. {
  701. hr = WBEM_E_CRITICAL_ERROR;
  702. //
  703. // inform WMI that action is complete with error (WBEM_E_CRITICAL_ERROR)
  704. //
  705. pSink->SetStatus(WBEM_STATUS_COMPLETE, hr, NULL, NULL);
  706. }
  707. return hr;
  708. }
  709. /*
  710. Routine Description:
  711. Name:
  712. CSceWmiProv::ExecQueryAsync
  713. Functionality:
  714. Execute the given query and return the results (objects) to WMI.
  715. Virtual:
  716. Yes.
  717. Arguments:
  718. QueryLanguage - the language. Currently, it's alway L"WQL".
  719. Query - the query itself
  720. lFlags - not used.
  721. pCtx - COM interface pointer that was passed around for WMI APIs.
  722. pSink - COM interface pointer to notify WMI of results (in this case
  723. it is used to notify WMI of the created object.
  724. Return Value:
  725. Success: Various success code. No guarantee to return WBEM_NO_ERROR.
  726. Failure: Various error code. It is either caused by Impersonation failure or
  727. failure to execute the query
  728. Notes:
  729. You should never call this directly. It's intended for WMI calls.
  730. */
  731. STDMETHODIMP CSceWmiProv::ExecQueryAsync (
  732. IN const BSTR QueryLanguage,
  733. IN const BSTR Query,
  734. IN long lFlags,
  735. IN IWbemContext * pCtx,
  736. IN IWbemObjectSink * pSink
  737. )
  738. {
  739. HRESULT hr = WBEM_NO_ERROR;
  740. //
  741. // our classes are following COM rule so that they won't throw. The following try-catch
  742. // is to guard against critical errors inside our code so that it won't crash the host process.
  743. //
  744. try
  745. {
  746. //
  747. // make sure impersonated
  748. //
  749. hr = CheckImpersonationLevel();
  750. if (SUCCEEDED(hr))
  751. {
  752. CRequestObject ReqObj(m_srpNamespace);
  753. hr = ReqObj.ExecQuery(Query, pSink, pCtx);
  754. //
  755. // inform WMI that action is complete with hr as result
  756. //
  757. pSink->SetStatus(0 ,hr , NULL, NULL);
  758. }
  759. }
  760. catch(...)
  761. {
  762. hr = WBEM_E_CRITICAL_ERROR;
  763. //
  764. // inform WMI that action is complete with error (WBEM_E_CRITICAL_ERROR)
  765. //
  766. pSink->SetStatus(WBEM_STATUS_COMPLETE, hr, NULL, NULL);
  767. }
  768. return hr;
  769. }
  770. /*
  771. Routine Description:
  772. Name:
  773. CreateDefLogFile
  774. Functionality:
  775. Global helper. Will create the default log file's directory. Also it will pass back
  776. the default log file's full path.
  777. Virtual:
  778. N/A.
  779. Arguments:
  780. pbstrDefLogFilePath - the default log file's path
  781. Return Value:
  782. Success: Various success code. No guarantee to return WBEM_NO_ERROR.
  783. Failure: Various error code. Any failure indicates failure to create the default log
  784. file directory, plus the out parameter will be NULL.
  785. Notes:
  786. (1) Default log file is located at sub-dir of the personal profile directory. Your call to this
  787. function may fail if you haven't impersonated the caller.
  788. */
  789. HRESULT CreateDefLogFile (
  790. OUT BSTR* pbstrDefLogFilePath
  791. )
  792. {
  793. //
  794. // make sure that parameter is good for output
  795. //
  796. if (pbstrDefLogFilePath == NULL)
  797. {
  798. return WBEM_E_INVALID_PARAMETER;
  799. }
  800. *pbstrDefLogFilePath = NULL;
  801. HRESULT hr = WBEM_NO_ERROR;
  802. HANDLE hToken = NULL;
  803. //
  804. // need the thread token to locate the profile directory
  805. //
  806. if (::OpenThreadToken(::GetCurrentThread(), TOKEN_QUERY, FALSE, &hToken))
  807. {
  808. //
  809. // try to get the size of buffer needed for the path
  810. //
  811. DWORD dwSize = 0;
  812. //
  813. // return result doesn't matter, but it shouldn't fail
  814. //
  815. ::GetUserProfileDirectory(hToken, NULL, &dwSize);
  816. //
  817. // got the buffer size
  818. //
  819. if (dwSize > 0)
  820. {
  821. //
  822. // need a buffer with enough room
  823. //
  824. DWORD dwDefSize = wcslen(pszDefLogFilePath);
  825. *pbstrDefLogFilePath = ::SysAllocStringLen(NULL, dwSize + dwDefSize + 1);
  826. //
  827. // for readability
  828. //
  829. LPWSTR pszLogFile = (LPWSTR)(*pbstrDefLogFilePath);
  830. if ((LPCWSTR)pszLogFile == NULL)
  831. {
  832. hr = WBEM_E_OUT_OF_MEMORY;
  833. }
  834. else if (::GetUserProfileDirectory(hToken, pszLogFile, &dwSize))
  835. {
  836. //
  837. // append the pszDefLogFilePath, plus the 0 terminator
  838. //
  839. ::memcpy(pszLogFile + wcslen(pszLogFile), pszDefLogFilePath, (dwDefSize + 1) * sizeof(WCHAR));
  840. long lLen = wcslen(pszLogFile) - 1;
  841. //
  842. // we only need the sub-directory name. Lookback to the last backslash or slash
  843. //
  844. while (lLen > 0 && pszLogFile[lLen] != L'\\' && pszLogFile[lLen] != L'/')
  845. {
  846. --lLen;
  847. }
  848. if (lLen > 0)
  849. {
  850. //
  851. // get rid of the trailing backslash if still have it (because it may have 2 backslashes)
  852. //
  853. if (pszLogFile[lLen-1] == L'\\' || pszLogFile[lLen-1] == L'/')
  854. {
  855. --lLen;
  856. }
  857. if (lLen > 0)
  858. {
  859. //
  860. // create a shorter bstr with the front of the pszLogFile
  861. //
  862. CComBSTR bstrLogPathDir = ::SysAllocStringLen(pszLogFile, lLen);
  863. if ((LPCWSTR)bstrLogPathDir != NULL)
  864. {
  865. //
  866. // now, create the directory. This will create all non-existent parent sub-directory as well!
  867. //
  868. if (SUCCEEDED(hr) && !::CreateDirectory(bstrLogPathDir, NULL))
  869. {
  870. //
  871. // GetLastError() eeds to be translated to HRESULT.
  872. // In case this is not an error, hr will be assigned to WBEM_NO_ERROR
  873. //
  874. DWORD dwError = GetLastError();
  875. if (dwError == ERROR_ALREADY_EXISTS)
  876. {
  877. hr = WBEM_NO_ERROR;
  878. }
  879. else
  880. {
  881. hr = ProvDosErrorToWbemError(dwError);
  882. }
  883. }
  884. }
  885. else
  886. {
  887. hr = WBEM_E_OUT_OF_MEMORY;
  888. }
  889. }
  890. }
  891. }
  892. }
  893. ::CloseHandle(hToken);
  894. }
  895. else
  896. {
  897. //
  898. // open thread token fails
  899. //
  900. //
  901. // GetLastError() eeds to be translated to HRESULT.
  902. // In case this is not an error, hr will be assigned to WBEM_NO_ERROR
  903. //
  904. hr = ProvDosErrorToWbemError(GetLastError());
  905. }
  906. //
  907. // if can't create the default log file, reset the default log file path
  908. //
  909. if (FAILED(hr) && *pbstrDefLogFilePath != NULL)
  910. {
  911. //
  912. // we have no default log file
  913. //
  914. ::SysFreeString(*pbstrDefLogFilePath);
  915. *pbstrDefLogFilePath = NULL;
  916. }
  917. return hr;
  918. }
  919. /*
  920. Routine Description:
  921. Name:
  922. CheckImpersonationLevel
  923. Functionality:
  924. Impersonate the calling thread.
  925. Virtual:
  926. N/A.
  927. Arguments:
  928. none
  929. Return Value:
  930. Success: Various success code. No guarantee to return WBEM_NO_ERROR.
  931. Failure: Various error code, but most noticeable is WBEM_E_ACCESS_DENIED.
  932. Notes:
  933. */
  934. HRESULT CheckImpersonationLevel()
  935. {
  936. //
  937. // we will assume access being denied
  938. //
  939. HRESULT hr = WBEM_E_ACCESS_DENIED;
  940. if (SUCCEEDED(CoImpersonateClient()))
  941. {
  942. //
  943. // Now, let's check the impersonation level. First, get the thread token
  944. //
  945. HANDLE hThreadTok;
  946. DWORD dwImp, dwBytesReturned;
  947. if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &hThreadTok ))
  948. {
  949. hr = WBEM_NO_ERROR;
  950. }
  951. else
  952. {
  953. if (GetTokenInformation(hThreadTok,
  954. TokenImpersonationLevel,
  955. &dwImp,
  956. sizeof(DWORD),
  957. &dwBytesReturned) )
  958. {
  959. //
  960. // Is the impersonation level Impersonate?
  961. //
  962. if (dwImp >= SecurityImpersonation)
  963. {
  964. hr = WBEM_S_NO_ERROR;
  965. }
  966. else
  967. {
  968. hr = WBEM_E_ACCESS_DENIED;
  969. }
  970. }
  971. else
  972. {
  973. hr = WBEM_E_FAILED;
  974. }
  975. CloseHandle(hThreadTok);
  976. }
  977. }
  978. return hr;
  979. }
  980. /*
  981. Routine Description:
  982. Name:
  983. CheckAndExpandPath
  984. Functionality:
  985. (1) Check if the in-bound parameter has a env variable or not.
  986. If yes, we will expand the variable and pass back the result via
  987. out parameter.
  988. (2) As a by product, it also returns the store type
  989. of the given path. Checking the store path is obviously what
  990. this function is designed for.
  991. (3) The output parameter will have double backslah for each single
  992. backslash of the input parameter.
  993. Virtual:
  994. N/A.
  995. Arguments:
  996. pszIn - the path to check and/or expand.
  997. bstrOut - the expanded path.
  998. pbSdb - if interested, we will determined it the path is a database
  999. file. We only recognize .sdb as database file.
  1000. Return Value:
  1001. Success: Various success code. No guarantee to return WBEM_NO_ERROR. If
  1002. an out parameter is given, that parameter will be filled with
  1003. appropriate information. Caller is responsible for releasing
  1004. the bstr.
  1005. Failure: Various error code. Any error indicates our failure to check or expand.
  1006. Notes:
  1007. */
  1008. HRESULT CheckAndExpandPath (
  1009. IN LPCWSTR pszIn,
  1010. OUT BSTR * bstrOut OPTIONAL,
  1011. OUT BOOL * pbSdb OPTIONAL
  1012. )
  1013. {
  1014. if ( pszIn == NULL)
  1015. {
  1016. return WBEM_E_INVALID_PARAMETER;
  1017. }
  1018. DWORD Len = wcslen(pszIn);
  1019. if ( Len <= 6 )
  1020. {
  1021. //
  1022. // x : .sdb or % % .sdb
  1023. //
  1024. return WBEM_E_INVALID_PARAMETER;
  1025. }
  1026. if (pbSdb)
  1027. {
  1028. if ( _wcsicmp(pszIn + Len - 4, L".sdb") == 0 )
  1029. {
  1030. //
  1031. // database
  1032. //
  1033. *pbSdb = TRUE;
  1034. }
  1035. else
  1036. {
  1037. *pbSdb = FALSE;
  1038. }
  1039. }
  1040. HRESULT hr = WBEM_NO_ERROR;
  1041. if ( bstrOut )
  1042. {
  1043. //
  1044. // expand environment variable
  1045. //
  1046. if ( wcsstr(pszIn, L"%") )
  1047. {
  1048. PWSTR pBuf=NULL;
  1049. PWSTR pBuf2=NULL;
  1050. DWORD dwSize = ExpandEnvironmentStrings(pszIn,NULL, 0);
  1051. if ( dwSize > 0 )
  1052. {
  1053. //
  1054. // allocate buffer big enough to have two \\s
  1055. //
  1056. pBuf = (PWSTR)LocalAlloc(LPTR, (dwSize+1)*sizeof(WCHAR));
  1057. if ( pBuf )
  1058. {
  1059. pBuf2 = (PWSTR)LocalAlloc(LPTR, (dwSize+256)*sizeof(WCHAR));
  1060. if ( pBuf2 )
  1061. {
  1062. DWORD dwNewSize = ExpandEnvironmentStrings(pszIn,pBuf, dwSize);
  1063. if ( dwNewSize > 0)
  1064. {
  1065. //
  1066. // convert the string from one \ to \\ (for use with WMI)
  1067. //
  1068. PWSTR pTemp1=pBuf, pTemp2=pBuf2;
  1069. while ( *pTemp1 != L'\0')
  1070. {
  1071. if ( *pTemp1 != L'\\')
  1072. {
  1073. *pTemp2++ = *pTemp1;
  1074. }
  1075. else if ( *(pTemp1+1) != L'\\')
  1076. {
  1077. //
  1078. // single back slash, add another one
  1079. //
  1080. *pTemp2++ = *pTemp1;
  1081. *pTemp2++ = L'\\';
  1082. }
  1083. else
  1084. {
  1085. //
  1086. // double back slashs, just copy
  1087. //
  1088. *pTemp2++ = *pTemp1++;
  1089. *pTemp2++ = *pTemp1;
  1090. }
  1091. pTemp1++;
  1092. }
  1093. *bstrOut = SysAllocString(pBuf2);
  1094. if ( *bstrOut == NULL ) {
  1095. hr = WBEM_E_OUT_OF_MEMORY;
  1096. }
  1097. }
  1098. LocalFree(pBuf2);
  1099. pBuf2 = NULL;
  1100. }
  1101. else
  1102. {
  1103. hr = WBEM_E_OUT_OF_MEMORY;
  1104. }
  1105. LocalFree(pBuf);
  1106. pBuf = NULL;
  1107. }
  1108. else
  1109. {
  1110. hr = WBEM_E_OUT_OF_MEMORY;
  1111. }
  1112. }
  1113. else
  1114. {
  1115. hr = WBEM_E_FAILED;
  1116. }
  1117. }
  1118. else
  1119. {
  1120. *bstrOut = SysAllocString(pszIn);
  1121. if ( *bstrOut == NULL )
  1122. {
  1123. return WBEM_E_OUT_OF_MEMORY;
  1124. }
  1125. }
  1126. }
  1127. return hr;
  1128. }
  1129. /*
  1130. Routine Description:
  1131. Name:
  1132. MakeSingleBackSlashPath
  1133. Functionality:
  1134. (1) Replace the double backslash with the given WCHAR (wc).
  1135. Virtual:
  1136. N/A.
  1137. Arguments:
  1138. pszIn - the path to be processed.
  1139. wc - the WCHAR that will be replacing the backslash.
  1140. bstrOut - the replaced path.
  1141. Return Value:
  1142. Success: Various success code. No guarantee to return WBEM_NO_ERROR.
  1143. Caller is responsible for releasing the bstr.
  1144. Failure: Various error code. Any error indicates our failure to do the replacement.
  1145. Notes:
  1146. */
  1147. HRESULT MakeSingleBackSlashPath (
  1148. IN LPCWSTR pszIn,
  1149. IN WCHAR wc,
  1150. OUT BSTR * bstrOut
  1151. )
  1152. {
  1153. if ( pszIn == NULL || bstrOut == NULL )
  1154. {
  1155. return WBEM_E_INVALID_PARAMETER;
  1156. }
  1157. //
  1158. // convert the string from two \ to one (for save in SCE store)
  1159. //
  1160. //
  1161. // two chars for the quotes
  1162. //
  1163. PWSTR pBuf2 = (PWSTR)LocalAlloc(LPTR, (wcslen(pszIn)+3)*sizeof(WCHAR));
  1164. if ( pBuf2 == NULL )
  1165. {
  1166. return WBEM_E_OUT_OF_MEMORY;
  1167. }
  1168. HRESULT hr = WBEM_S_NO_ERROR;
  1169. PWSTR pTemp1=(PWSTR)pszIn, pTemp2=pBuf2;
  1170. while ( *pTemp1 != L'\0')
  1171. {
  1172. if ( *pTemp1 != L'\\' || *(pTemp1 + 1) != L'\\' )
  1173. {
  1174. //
  1175. // not back slash or single back slash
  1176. //
  1177. *pTemp2++ = *pTemp1;
  1178. }
  1179. else
  1180. {
  1181. //
  1182. // double back slashs, remove one
  1183. //
  1184. *pTemp2++ = wc;
  1185. pTemp1++;
  1186. }
  1187. pTemp1++;
  1188. }
  1189. *bstrOut = SysAllocString(pBuf2);
  1190. if ( *bstrOut == NULL )
  1191. {
  1192. hr = WBEM_E_OUT_OF_MEMORY;
  1193. }
  1194. LocalFree(pBuf2);
  1195. pBuf2 = NULL;
  1196. return hr;
  1197. }
  1198. /*
  1199. Routine Description:
  1200. Name:
  1201. ConvertToDoubleBackSlashPath
  1202. Functionality:
  1203. The inverse function of MakeSingleBackSlashPath, except that the character
  1204. this function looks for is the given parameter wc.
  1205. Virtual:
  1206. N/A.
  1207. Arguments:
  1208. pszIn - the path to be processed.
  1209. wc - the WCHAR that will be replaced during the operation.
  1210. bstrOut - the replaced path.
  1211. Return Value:
  1212. Success: Various success code. No guarantee to return WBEM_NO_ERROR.
  1213. Caller is responsible for releasing the bstr.
  1214. Failure: Various error code. Any error indicates our failure to do the replacement.
  1215. Notes:
  1216. */
  1217. HRESULT ConvertToDoubleBackSlashPath (
  1218. IN LPCWSTR strIn,
  1219. IN WCHAR wc,
  1220. OUT BSTR * bstrOut
  1221. )
  1222. {
  1223. if ( strIn == NULL || bstrOut == NULL )
  1224. {
  1225. return WBEM_E_INVALID_PARAMETER;
  1226. }
  1227. HRESULT hr=WBEM_S_NO_ERROR;
  1228. LPWSTR pBuf=NULL;
  1229. //
  1230. // allocate buffer big enough to have two \\s
  1231. //
  1232. pBuf = (PWSTR)LocalAlloc(LPTR, (wcslen(strIn)+256)*sizeof(WCHAR));
  1233. if ( pBuf == NULL ) return WBEM_E_OUT_OF_MEMORY;
  1234. //
  1235. // convert the string from wc to \\ (for use with WMI)
  1236. //
  1237. LPCWSTR pTemp1=strIn;
  1238. LPWSTR pTemp2=pBuf;
  1239. while ( *pTemp1 != L'\0')
  1240. {
  1241. if ( *pTemp1 != wc)
  1242. {
  1243. *pTemp2++ = *pTemp1;
  1244. }
  1245. else if ( *(pTemp1+1) != wc)
  1246. {
  1247. //
  1248. // single wc, put two back slashes
  1249. //
  1250. *pTemp2++ = L'\\';
  1251. *pTemp2++ = L'\\';
  1252. }
  1253. else
  1254. {
  1255. //
  1256. // double back slashs (or double wc), just copy
  1257. //
  1258. *pTemp2++ = *pTemp1++;
  1259. *pTemp2++ = *pTemp1;
  1260. }
  1261. //
  1262. // move to next wchar
  1263. //
  1264. pTemp1++;
  1265. }
  1266. *bstrOut = SysAllocString(pBuf);
  1267. if ( *bstrOut == NULL )
  1268. {
  1269. hr = WBEM_E_OUT_OF_MEMORY;
  1270. }
  1271. LocalFree(pBuf);
  1272. return hr;
  1273. }
  1274. /*
  1275. Routine Description:
  1276. Name:
  1277. GetWbemPathParser
  1278. Functionality:
  1279. wrapper for the CoCreateInstance of the wbem Path parser
  1280. Virtual:
  1281. N/A.
  1282. Arguments:
  1283. ppPathParser - the output parameter receiving the wbem path parser.
  1284. Return Value:
  1285. Success: Various success code. No guarantee to return WBEM_NO_ERROR.
  1286. Caller is responsible for releasing the bstr.
  1287. Failure: Various error code. Any error indicates failure to create the wbem path parser.
  1288. Notes:
  1289. (1) Of course, as always, caller is responsible for releasing the out parameter.
  1290. */
  1291. HRESULT GetWbemPathParser (
  1292. OUT IWbemPath** ppPathParser
  1293. )
  1294. {
  1295. return ::CoCreateInstance(CLSID_WbemDefPath, 0, CLSCTX_INPROC_SERVER, IID_IWbemPath, (LPVOID *) ppPathParser);
  1296. }
  1297. /*
  1298. Routine Description:
  1299. Name:
  1300. GetWbemQuery
  1301. Functionality:
  1302. wrapper for the CoCreateInstance of the wbem query parser
  1303. Virtual:
  1304. N/A.
  1305. Arguments:
  1306. ppQuery - the output parameter receiving the wbem query parser.
  1307. Return Value:
  1308. Success: Various success code. No guarantee to return WBEM_NO_ERROR.
  1309. Caller is responsible for releasing the bstr.
  1310. Failure: Various error code. Any error indicates failure to create the wbem path parser.
  1311. Notes:
  1312. (1) Of course, as always, caller is responsible for releasing the out parameter.
  1313. */
  1314. HRESULT GetWbemQuery (
  1315. OUT IWbemQuery** ppQuery
  1316. )
  1317. {
  1318. return ::CoCreateInstance(CLSID_WbemQuery, 0, CLSCTX_INPROC_SERVER, IID_IWbemQuery, (LPVOID *) ppQuery);
  1319. }