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.

912 lines
24 KiB

  1. // service.cpp: implementation of the CGeneralService class.
  2. //
  3. // Copyright (c)1997-1999 Microsoft Corporation
  4. //
  5. //////////////////////////////////////////////////////////////////////
  6. #include "precomp.h"
  7. #include "service.h"
  8. #include "persistmgr.h"
  9. #include <io.h>
  10. #include "requestobject.h"
  11. const DWORD dwDefaultStartupType = 2;
  12. /*
  13. Routine Description:
  14. Name:
  15. CGeneralService::CGeneralService
  16. Functionality:
  17. This is the constructor. Pass along the parameters to the base class
  18. Virtual:
  19. No (you know that, constructor won't be virtual!)
  20. Arguments:
  21. pKeyChain - Pointer to the ISceKeyChain COM interface which is prepared
  22. by the caller who constructs this instance.
  23. pNamespace - Pointer to WMI namespace of our provider (COM interface).
  24. Passed along by the caller. Must not be NULL.
  25. pCtx - Pointer to WMI context object (COM interface). Passed along
  26. by the caller. It's up to WMI whether this interface pointer is NULL or not.
  27. Return Value:
  28. None as any constructor
  29. Notes:
  30. if you create any local members, think about initialize them here
  31. */
  32. CGeneralService::CGeneralService (
  33. IN ISceKeyChain * pKeyChain,
  34. IN IWbemServices * pNamespace,
  35. IN IWbemContext * pCtx
  36. )
  37. :
  38. CGenericClass(pKeyChain, pNamespace, pCtx)
  39. {
  40. }
  41. /*
  42. Routine Description:
  43. Name:
  44. CGeneralService::~CGeneralService
  45. Functionality:
  46. Destructor. Necessary as good C++ discipline since we have virtual functions.
  47. Virtual:
  48. Yes.
  49. Arguments:
  50. none as any destructor
  51. Return Value:
  52. None as any destructor
  53. Notes:
  54. if you create any local members, think about whether
  55. there is any need for a non-trivial destructor
  56. */
  57. CGeneralService::~CGeneralService()
  58. {
  59. }
  60. /*
  61. Routine Description:
  62. Name:
  63. CGeneralService::CreateObject
  64. Functionality:
  65. Create WMI objects (Sce_SystemService). Depending on parameter atAction,
  66. this creation may mean:
  67. (a) Get a single instance (atAction == ACTIONTYPE_GET)
  68. (b) Get several instances satisfying some criteria (atAction == ACTIONTYPE_QUERY)
  69. (c) Delete an instance (atAction == ACTIONTYPE_DELETE)
  70. Virtual:
  71. Yes.
  72. Arguments:
  73. pHandler - COM interface pointer for notifying WMI for creation result.
  74. atAction - Get single instance ACTIONTYPE_GET
  75. Get several instances ACTIONTYPE_QUERY
  76. Delete a single instance ACTIONTYPE_DELETE
  77. Return Value:
  78. Success: it must return success code (use SUCCEEDED to test). It is
  79. not guaranteed to return WBEM_NO_ERROR. The returned objects are indicated to WMI,
  80. not directly passed back via parameters.
  81. Failure: Various errors may occurs. Except WBEM_E_NOT_FOUND, any such error should indicate
  82. the failure of getting the wanted instance. If WBEM_E_NOT_FOUND is returned in querying
  83. situations, this may not be an error depending on caller's intention.
  84. Notes:
  85. */
  86. HRESULT
  87. CGeneralService::CreateObject (
  88. IN IWbemObjectSink * pHandler,
  89. IN ACTIONTYPE atAction
  90. )
  91. {
  92. //
  93. // we know how to:
  94. // Get single instance ACTIONTYPE_GET
  95. // Delete a single instance ACTIONTYPE_DELETE
  96. // Get several instances ACTIONTYPE_QUERY
  97. //
  98. if ( ACTIONTYPE_GET != atAction &&
  99. ACTIONTYPE_DELETE != atAction &&
  100. ACTIONTYPE_QUERY != atAction )
  101. {
  102. return WBEM_E_NOT_SUPPORTED;
  103. }
  104. //
  105. // We must have the pStorePath property because that is where
  106. // our instance is stored.
  107. // m_srpKeyChain->GetKeyPropertyValue WBEM_S_FALSE if the key is not recognized
  108. // So, we need to test against WBEM_S_FALSE if the property is mandatory
  109. //
  110. CComVariant varStorePath;
  111. HRESULT hr = m_srpKeyChain->GetKeyPropertyValue(pStorePath, &varStorePath);
  112. CComVariant varService;
  113. if (SUCCEEDED(hr) && hr != WBEM_S_FALSE)
  114. {
  115. hr = m_srpKeyChain->GetKeyPropertyValue(pService, &varService);
  116. //
  117. // unless it's querying, no complete key info means we can't get the single instance
  118. //
  119. if (hr == WBEM_S_FALSE && (ACTIONTYPE_QUERY != atAction) )
  120. {
  121. hr = WBEM_E_NOT_FOUND;
  122. }
  123. }
  124. else if (hr == WBEM_S_FALSE)
  125. {
  126. hr = WBEM_E_NOT_FOUND;
  127. }
  128. if (FAILED(hr))
  129. {
  130. return hr;
  131. }
  132. //
  133. // has a valid store path
  134. //
  135. if (varStorePath.vt == VT_BSTR)
  136. {
  137. //
  138. // Prepare a store (for persistence) for this store path (file)
  139. //
  140. CSceStore SceStore;
  141. hr = SceStore.SetPersistPath(varStorePath.bstrVal);
  142. if ( SUCCEEDED(hr) )
  143. {
  144. //
  145. // make sure the store (just a file) really exists. The raw path
  146. // may contain env variables, so we need the expanded path
  147. //
  148. DWORD dwAttrib = GetFileAttributes(SceStore.GetExpandedPath());
  149. if ( dwAttrib != -1 )
  150. {
  151. //
  152. // make sure our store is valid
  153. //
  154. if ( SceStore.GetStoreType() < SCE_INF_FORMAT ||
  155. SceStore.GetStoreType() > SCE_JET_ANALYSIS_REQUIRED )
  156. {
  157. hr = WBEM_E_INVALID_PARAMETER;
  158. }
  159. if ( SUCCEEDED(hr) )
  160. {
  161. if ( ACTIONTYPE_DELETE == atAction )
  162. {
  163. hr = DeleteInstance(pHandler, &SceStore, (varService.vt == VT_BSTR) ? varService.bstrVal : NULL);
  164. }
  165. else
  166. {
  167. BOOL bPostFilter=TRUE;
  168. DWORD dwCount = 0;
  169. m_srpKeyChain->GetKeyPropertyCount(&dwCount);
  170. if ( varService.vt == VT_EMPTY && dwCount == 1 )
  171. {
  172. //
  173. // something else is specified in the path
  174. // have filter on
  175. //
  176. bPostFilter = FALSE;
  177. }
  178. hr = ConstructInstance(pHandler,
  179. &SceStore,
  180. varStorePath.bstrVal,
  181. (varService.vt == VT_BSTR) ? varService.bstrVal : NULL,
  182. bPostFilter);
  183. }
  184. }
  185. }
  186. else
  187. {
  188. hr = WBEM_E_NOT_FOUND;
  189. }
  190. }
  191. }
  192. return hr;
  193. }
  194. /*
  195. Routine Description:
  196. Name:
  197. CGeneralService::PutInst
  198. Functionality:
  199. Put an instance as instructed by WMI. Since this class implements Sce_SystemService,
  200. which is persistence oriented, this will cause the Sce_SystemService object's property
  201. information to be saved in our store.
  202. Virtual:
  203. Yes.
  204. Arguments:
  205. pInst - COM interface pointer to the WMI class (Sce_SystemService) object.
  206. pHandler - COM interface pointer for notifying WMI of any events.
  207. pCtx - COM interface pointer. This interface is just something we pass around.
  208. WMI may mandate it (not now) in the future. But we never construct
  209. such an interface and so, we just pass around for various WMI API's
  210. Return Value:
  211. Success: it must return success code (use SUCCEEDED to test). It is
  212. not guaranteed to return WBEM_NO_ERROR.
  213. Failure: Various errors may occurs. Any such error should indicate the failure of persisting
  214. the instance.
  215. Notes:
  216. Since GetProperty will return a success code (WBEM_S_RESET_TO_DEFAULT) when the
  217. requested property is not present, don't simply use SUCCEEDED or FAILED macros
  218. to test for the result of retrieving a property.
  219. */
  220. HRESULT
  221. CGeneralService::PutInst (
  222. IN IWbemClassObject * pInst,
  223. IN IWbemObjectSink * pHandler,
  224. IN IWbemContext * pCtx
  225. )
  226. {
  227. HRESULT hr = WBEM_E_INVALID_PARAMETER;
  228. CComBSTR bstrObjPath;
  229. CComBSTR bstrSDDL;
  230. DWORD mode;
  231. CSceStore SceStore;
  232. //
  233. // CScePropertyMgr helps us to access WMI object's properties
  234. // create an instance and attach the WMI object to it.
  235. // This will always succeed.
  236. //
  237. CScePropertyMgr ScePropMgr;
  238. ScePropMgr.Attach(pInst);
  239. //
  240. // the use of the macro SCE_PROV_IfErrorGotoCleanup cause
  241. // a "goto CleanUp;" with hr set to the return value from
  242. // the function (macro parameter)
  243. //
  244. // get service name, can't be NULL
  245. // no validation is needed because we should allow a template w/ any service defined
  246. SCE_PROV_IfErrorGotoCleanup(ScePropMgr.GetProperty(pService, &bstrObjPath));
  247. if ( hr == WBEM_S_RESET_TO_DEFAULT)
  248. {
  249. hr = WBEM_E_ILLEGAL_NULL;
  250. goto CleanUp;
  251. }
  252. //
  253. // get startuptype, default to 2 (dwDefaultStartupType)
  254. //
  255. SCE_PROV_IfErrorGotoCleanup(ScePropMgr.GetProperty(pStartupMode, &mode));
  256. if ( hr == WBEM_S_RESET_TO_DEFAULT)
  257. mode = dwDefaultStartupType;
  258. //
  259. // get SDDLString, can't be NULL
  260. //
  261. SCE_PROV_IfErrorGotoCleanup(ScePropMgr.GetProperty(pSDDLString, &bstrSDDL));
  262. if ( hr == WBEM_S_RESET_TO_DEFAULT)
  263. {
  264. hr = WBEM_E_ILLEGAL_NULL;
  265. goto CleanUp;
  266. }
  267. //
  268. // Attach the WMI object instance to the store and let the store know that
  269. // it's store is given by the pStorePath property of the instance.
  270. //
  271. SceStore.SetPersistProperties(pInst, pStorePath);
  272. //
  273. // now save the info to file
  274. //
  275. hr = SaveSettingsToStore(&SceStore,
  276. bstrObjPath,
  277. mode,
  278. bstrSDDL
  279. );
  280. CleanUp:
  281. return hr;
  282. }
  283. /*
  284. Routine Description:
  285. Name:
  286. CGeneralService::ConstructInstance
  287. Functionality:
  288. This is private function to create an instance of Sce_SystemService.
  289. Virtual:
  290. No.
  291. Arguments:
  292. pHandler - COM interface pointer for notifying WMI of any events.
  293. pSceStore - Pointer to our store. It must have been appropriately set up.
  294. wszLogStorePath - store path, a key property of Sce_SystemService class.
  295. wszObjName - a corresponding key property of Sce_SystemService class.
  296. bPostFilter - Controls how WMI will be informed with pHandler->SetStatus.
  297. Return Value:
  298. Success: it must return success code (use SUCCEEDED to test). It is
  299. not guaranteed to return WBEM_NO_ERROR.
  300. Failure: Various errors may occurs. Any such error should indicate the creating the instance.
  301. Notes:
  302. */
  303. HRESULT CGeneralService::ConstructInstance (
  304. IN IWbemObjectSink * pHandler,
  305. IN CSceStore * pSceStore,
  306. IN LPCWSTR wszLogStorePath,
  307. IN LPCWSTR wszObjName,
  308. IN BOOL bPostFilter
  309. )
  310. {
  311. //
  312. // ask SCE to read a gigantic structure out from the store. Only SCE
  313. // knows now to release the memory. Don't just delete it! Use our CSceStore
  314. // to do the releasing (FreeSecurityProfileInfo)
  315. //
  316. PSCE_PROFILE_INFO pInfo=NULL;
  317. //
  318. // string version of security descriptor
  319. //
  320. PWSTR strSD = NULL;
  321. HRESULT hr = pSceStore->GetSecurityProfileInfo(
  322. AREA_SYSTEM_SERVICE,
  323. &pInfo,
  324. NULL
  325. );
  326. if (FAILED(hr))
  327. {
  328. return hr;
  329. }
  330. //
  331. // we have to search for the service name in the returned list
  332. //
  333. PSCE_SERVICES pInfoService = pInfo->pServices;
  334. if ( wszObjName )
  335. {
  336. while ( pInfoService )
  337. {
  338. if ( pInfoService->ServiceName == NULL )
  339. {
  340. continue;
  341. }
  342. if ( _wcsicmp(pInfoService->ServiceName, wszObjName)== 0 )
  343. {
  344. break;
  345. }
  346. pInfoService = pInfoService->Next;
  347. }
  348. //
  349. // if the service information buffer is empty, treat it as "not found"
  350. //
  351. if ( pInfoService == NULL )
  352. {
  353. hr = WBEM_E_NOT_FOUND;
  354. }
  355. }
  356. if ( SUCCEEDED(hr) )
  357. {
  358. CComBSTR bstrLogOut;
  359. PSCE_SERVICES pServ = pInfoService;
  360. //
  361. // CScePropertyMgr helps us to access WMI object's properties.
  362. //
  363. CScePropertyMgr ScePropMgr;
  364. hr = MakeSingleBackSlashPath(wszLogStorePath, L'\\', &bstrLogOut);
  365. for ( pServ=pInfoService; pServ != NULL; pServ = pServ->Next )
  366. {
  367. if ( pServ->General.pSecurityDescriptor )
  368. {
  369. //
  370. // convert security descriptor to string
  371. //
  372. DWORD dSize=0;
  373. SCESTATUS rc;
  374. if ( SCESTATUS_SUCCESS != (rc=SceSvcConvertSDToText(pServ->General.pSecurityDescriptor,
  375. pServ->SeInfo,
  376. &strSD,
  377. &dSize
  378. )) )
  379. {
  380. //
  381. // SCE returned errors needs to be translated to HRESULT.
  382. //
  383. hr = ProvDosErrorToWbemError(ProvSceStatusToDosError(rc));
  384. goto CleanUp;
  385. }
  386. }
  387. CComPtr<IWbemClassObject> srpObj;
  388. //
  389. // the use of the macro SCE_PROV_IfErrorGotoCleanup cause
  390. // a "goto CleanUp;" with hr set to the return value from
  391. // the function (macro parameter)
  392. //
  393. SCE_PROV_IfErrorGotoCleanup(SpawnAnInstance(&srpObj));
  394. //
  395. // attach a different WMI object to the proeprty mgr.
  396. // This will always succeed.
  397. //
  398. ScePropMgr.Attach(srpObj);
  399. SCE_PROV_IfErrorGotoCleanup(ScePropMgr.PutProperty(pStorePath, bstrLogOut));
  400. SCE_PROV_IfErrorGotoCleanup(ScePropMgr.PutProperty(pService, pServ->ServiceName));
  401. DWORD dwStartUp = pServ->Startup;
  402. SCE_PROV_IfErrorGotoCleanup(ScePropMgr.PutProperty(pStartupMode, dwStartUp));
  403. if ( strSD )
  404. {
  405. SCE_PROV_IfErrorGotoCleanup(ScePropMgr.PutProperty(pSDDLString, strSD));
  406. }
  407. //
  408. // do the necessary gestures to WMI.
  409. // the use of WBEM_STATUS_REQUIREMENTS in SetStatus is not documented by WMI
  410. // at this point. Consult WMI team for detail if you suspect problems with
  411. // the use of WBEM_STATUS_REQUIREMENTS
  412. //
  413. if ( !bPostFilter ) {
  414. pHandler->SetStatus(WBEM_STATUS_REQUIREMENTS, S_FALSE, NULL, NULL);
  415. } else {
  416. pHandler->SetStatus(WBEM_STATUS_REQUIREMENTS, S_OK, NULL, NULL);
  417. }
  418. //
  419. // pass the new instance to WMI
  420. //
  421. hr = pHandler->Indicate(1, &srpObj);
  422. if ( wszObjName )
  423. {
  424. // single instance only
  425. break;
  426. }
  427. }
  428. }
  429. CleanUp:
  430. pSceStore->FreeSecurityProfileInfo(pInfo);
  431. if ( strSD )
  432. {
  433. LocalFree(strSD);
  434. }
  435. return hr;
  436. }
  437. /*
  438. Routine Description:
  439. Name:
  440. CGeneralService::DeleteInstance
  441. Functionality:
  442. remove an instance of Sce_SystemService from the specified store.
  443. Virtual:
  444. No.
  445. Arguments:
  446. pHandler - COM interface pointer for notifying WMI of any events.
  447. pSceStore - Pointer to our store. It must have been appropriately set up.
  448. wszObjName - property of the Sce_SystemService class.
  449. Return Value:
  450. see SaveSettingsToStore.
  451. Notes:
  452. */
  453. HRESULT CGeneralService::DeleteInstance (
  454. IN IWbemObjectSink * pHandler,
  455. IN CSceStore * pSceStore,
  456. IN LPCWSTR wszObjName
  457. )
  458. {
  459. return SaveSettingsToStore(pSceStore, wszObjName,SCE_NO_VALUE, NULL);
  460. }
  461. /*
  462. Routine Description:
  463. Name:
  464. CGeneralService::SaveSettingsToStore
  465. Functionality:
  466. With all the properties of a Sce_SystemService, this function just saves
  467. the instance properties to our store.
  468. Virtual:
  469. No.
  470. Arguments:
  471. pSceStore - the store.
  472. wszObjName - a corresponding key property of Sce_SystemService class.
  473. Startup - another corresponding property of the Sce_SystemService class.
  474. wszSDDL - another corresponding property of the Sce_SystemService class.
  475. Return Value:
  476. Success: it must return success code (use SUCCEEDED to test). It is
  477. not guaranteed to return WBEM_NO_ERROR.
  478. Failure: Various errors may occurs. Any error indicates the failure to save the instance.
  479. Notes:
  480. */
  481. HRESULT CGeneralService::SaveSettingsToStore (
  482. IN CSceStore * pSceStore,
  483. IN LPCWSTR wszObjName,
  484. IN DWORD Startup,
  485. IN LPCWSTR wszSDDL
  486. )
  487. {
  488. DWORD dwDump;
  489. //
  490. // For a new .inf file. Write an empty buffer to the file
  491. // will creates the file with right header/signature/unicode format
  492. // this is harmless for existing files.
  493. // For database store, this is a no-op.
  494. //
  495. HRESULT hr = pSceStore->WriteSecurityProfileInfo(
  496. AreaBogus,
  497. (PSCE_PROFILE_INFO)&dwDump,
  498. NULL,
  499. false
  500. );
  501. if (FAILED(hr))
  502. {
  503. return hr;
  504. }
  505. //
  506. // ask SCE to read a gigantic structure out from the store. Only SCE
  507. // knows now to release the memory. Don't just delete it! Use our CSceStore
  508. // to do the releasing (FreeSecurityProfileInfo)
  509. //
  510. PSCE_PROFILE_INFO pInfo = NULL;
  511. hr = pSceStore->GetSecurityProfileInfo(
  512. AREA_SYSTEM_SERVICE,
  513. &pInfo,
  514. NULL
  515. );
  516. if ( SUCCEEDED(hr) )
  517. {
  518. //
  519. // for INF format, we have to search for the servic name in the returned array
  520. //
  521. PSCE_SERVICES pInfoService = pInfo->pServices;
  522. PSCE_SERVICES pParent = NULL;
  523. DWORD i=0;
  524. while ( pInfoService )
  525. {
  526. if ( pInfoService->ServiceName == NULL )
  527. {
  528. continue;
  529. }
  530. if ( _wcsicmp(pInfoService->ServiceName, wszObjName)== 0 )
  531. {
  532. break;
  533. }
  534. pParent = pInfoService;
  535. pInfoService = pInfoService->Next;
  536. }
  537. if ( pInfoService )
  538. {
  539. //
  540. // find it
  541. //
  542. if ( Startup == SCE_NO_VALUE || wszSDDL == NULL )
  543. {
  544. //
  545. // delete it
  546. //
  547. if ( pParent )
  548. {
  549. pParent->Next = pInfoService->Next;
  550. }
  551. else
  552. {
  553. pInfo->pServices = pInfoService->Next;
  554. }
  555. //
  556. // free buffer
  557. //
  558. pInfoService->Next = NULL;
  559. SceFreeMemory(pInfoService, SCE_STRUCT_SERVICES);
  560. }
  561. else
  562. {
  563. //
  564. // modify it
  565. //
  566. pInfoService->Startup = (BYTE)Startup;
  567. SECURITY_INFORMATION SeInfo=0;
  568. PSECURITY_DESCRIPTOR pSD=NULL;
  569. DWORD dSize=0;
  570. SCESTATUS rc = SceSvcConvertTextToSD ((PWSTR)wszSDDL, &pSD, &dSize, &SeInfo);
  571. if ( rc == SCESTATUS_SUCCESS && pSD )
  572. {
  573. if ( pInfoService->General.pSecurityDescriptor )
  574. {
  575. LocalFree(pInfoService->General.pSecurityDescriptor);
  576. }
  577. pInfoService->General.pSecurityDescriptor = pSD;
  578. pSD = NULL;
  579. pInfoService->SeInfo = SeInfo;
  580. }
  581. else
  582. {
  583. //
  584. // SCE returned errors needs to be translated to HRESULT.
  585. //
  586. hr = ProvDosErrorToWbemError(ProvSceStatusToDosError(rc));
  587. }
  588. }
  589. if ( SUCCEEDED(hr) )
  590. {
  591. //
  592. // write the section header
  593. //
  594. hr = pSceStore->WriteSecurityProfileInfo(
  595. AREA_SYSTEM_SERVICE,
  596. pInfo,
  597. NULL,
  598. false // not appending
  599. );
  600. }
  601. }
  602. else
  603. {
  604. //
  605. // not found
  606. //
  607. if ( Startup == SCE_NO_VALUE || wszSDDL == NULL )
  608. {
  609. //
  610. // try to delete non exist object
  611. //
  612. hr = WBEM_E_NOT_FOUND;
  613. }
  614. else
  615. {
  616. //
  617. // add this one in
  618. //
  619. SCE_SERVICES addService;
  620. SECURITY_INFORMATION SeInfo=0;
  621. PSECURITY_DESCRIPTOR pSD=NULL;
  622. DWORD dSize=0;
  623. SCESTATUS rc = SceSvcConvertTextToSD ((PWSTR)wszSDDL, &pSD, &dSize, &SeInfo);
  624. if ( rc == SCESTATUS_SUCCESS && pSD )
  625. {
  626. addService.ServiceName = (PWSTR)wszObjName;
  627. addService.DisplayName = NULL;
  628. addService.Status = 0;
  629. addService.Startup = (BYTE)Startup;
  630. addService.General.pSecurityDescriptor = pSD;
  631. addService.SeInfo = SeInfo;
  632. addService.Next = NULL;
  633. //
  634. // set the temp buffer pointer to pInfo to set to the store
  635. //
  636. pInfoService = pInfo->pServices;
  637. pInfo->pServices = &addService;
  638. //
  639. // append this item to the section
  640. //
  641. hr = pSceStore->WriteSecurityProfileInfo(
  642. AREA_SYSTEM_SERVICE,
  643. pInfo,
  644. NULL,
  645. true // appending
  646. );
  647. //
  648. // reset the buffer pointer
  649. //
  650. pInfo->pServices = pInfoService;
  651. }
  652. if ( rc != SCESTATUS_SUCCESS )
  653. {
  654. //
  655. // SCE returned errors needs to be translated to HRESULT.
  656. //
  657. hr = ProvDosErrorToWbemError(ProvSceStatusToDosError(rc));
  658. }
  659. if ( pSD )
  660. {
  661. LocalFree(pSD);
  662. }
  663. }
  664. }
  665. }
  666. pSceStore->FreeSecurityProfileInfo(pInfo);
  667. return hr;
  668. }