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.

766 lines
20 KiB

  1. // Regvalue.cpp: implementation of the CRegistryValue class.
  2. //
  3. // Copyright (c)1997-1999 Microsoft Corporation
  4. //
  5. //////////////////////////////////////////////////////////////////////
  6. #include "precomp.h"
  7. #include "regvalue.h"
  8. #include "persistmgr.h"
  9. #include <io.h>
  10. #include "requestobject.h"
  11. /*
  12. Routine Description:
  13. Name:
  14. CRegistryValue::CRegistryValue
  15. Functionality:
  16. This is the constructor. Pass along the parameters to the base class
  17. Virtual:
  18. No (you know that, constructor won't be virtual!)
  19. Arguments:
  20. pKeyChain - Pointer to the ISceKeyChain COM interface which is prepared
  21. by the caller who constructs this instance.
  22. pNamespace - Pointer to WMI namespace of our provider (COM interface).
  23. Passed along by the caller. Must not be NULL.
  24. pCtx - Pointer to WMI context object (COM interface). Passed along
  25. by the caller. It's up to WMI whether this interface pointer is NULL or not.
  26. Return Value:
  27. None as any constructor
  28. Notes:
  29. if you create any local members, think about initialize them here
  30. */
  31. CRegistryValue::CRegistryValue (
  32. IN ISceKeyChain * pKeyChain,
  33. IN IWbemServices * pNamespace,
  34. IN IWbemContext * pCtx
  35. )
  36. :
  37. CGenericClass(pKeyChain, pNamespace, pCtx)
  38. {
  39. }
  40. /*
  41. Routine Description:
  42. Name:
  43. CRegistryValue::~CRGroups
  44. Functionality:
  45. Destructor. Necessary as good C++ discipline since we have virtual functions.
  46. Virtual:
  47. Yes.
  48. Arguments:
  49. none as any destructor
  50. Return Value:
  51. None as any destructor
  52. Notes:
  53. if you create any local members, think about whether
  54. there is any need for a non-trivial destructor
  55. */
  56. CRegistryValue::~CRegistryValue ()
  57. {
  58. }
  59. /*
  60. Routine Description:
  61. Name:
  62. CRegistryValue::CreateObject
  63. Functionality:
  64. Create WMI objects (Sce_RegistryValue). Depending on parameter atAction,
  65. this creation may mean:
  66. (a) Get a single instance (atAction == ACTIONTYPE_GET)
  67. (b) Get several instances satisfying some criteria (atAction == ACTIONTYPE_QUERY)
  68. (c) Delete an instance (atAction == ACTIONTYPE_DELETE)
  69. Virtual:
  70. Yes.
  71. Arguments:
  72. pHandler - COM interface pointer for notifying WMI for creation result.
  73. atAction - Get single instance ACTIONTYPE_GET
  74. Get several instances ACTIONTYPE_QUERY
  75. Delete a single instance ACTIONTYPE_DELETE
  76. Return Value:
  77. Success: it must return success code (use SUCCEEDED to test). It is
  78. not guaranteed to return WBEM_NO_ERROR. The returned objects are indicated to WMI,
  79. not directly passed back via parameters.
  80. Failure: Various errors may occurs. Except WBEM_E_NOT_FOUND, any such error should indicate
  81. the failure of getting the wanted instance. If WBEM_E_NOT_FOUND is returned in querying
  82. situations, this may not be an error depending on caller's intention.
  83. Notes:
  84. */
  85. HRESULT
  86. CRegistryValue::CreateObject (
  87. IN IWbemObjectSink * pHandler,
  88. IN ACTIONTYPE atAction
  89. )
  90. {
  91. //
  92. // we know how to:
  93. // Get single instance ACTIONTYPE_GET
  94. // Delete a single instance ACTIONTYPE_DELETE
  95. // Get several instances ACTIONTYPE_QUERY
  96. //
  97. if ( ACTIONTYPE_GET != atAction &&
  98. ACTIONTYPE_DELETE != atAction &&
  99. ACTIONTYPE_QUERY != atAction )
  100. {
  101. return WBEM_E_NOT_SUPPORTED;
  102. }
  103. //
  104. // We must have the pStorePath property because that is where
  105. // our instance is stored.
  106. // m_srpKeyChain->GetKeyPropertyValue WBEM_S_FALSE if the key is not recognized
  107. // So, we need to test against WBEM_S_FALSE if the property is mandatory
  108. //
  109. CComVariant varStorePath;
  110. HRESULT hr = m_srpKeyChain->GetKeyPropertyValue(pStorePath, &varStorePath);
  111. if (SUCCEEDED(hr) && hr != WBEM_S_FALSE && varStorePath.vt == VT_BSTR)
  112. {
  113. //
  114. // search for regitry value path
  115. //
  116. CComVariant varPath;
  117. hr = m_srpKeyChain->GetKeyPropertyValue(pPath, &varPath);
  118. if (FAILED(hr))
  119. {
  120. return hr;
  121. }
  122. else if (hr == WBEM_S_FALSE && (ACTIONTYPE_QUERY != atAction) )
  123. {
  124. return WBEM_E_NOT_FOUND;
  125. }
  126. //
  127. // Prepare a store (for persistence) for this store path (file)
  128. //
  129. CSceStore SceStore;
  130. hr = SceStore.SetPersistPath(varStorePath.bstrVal);
  131. if ( SUCCEEDED(hr) ) {
  132. //
  133. // make sure the store (just a file) really exists. The raw path
  134. // may contain env variables, so we need the expanded path
  135. //
  136. DWORD dwAttrib = GetFileAttributes(SceStore.GetExpandedPath());
  137. if ( dwAttrib != -1 ) {
  138. //
  139. // this file exists
  140. //
  141. DWORD dwCount = 0;
  142. m_srpKeyChain->GetKeyPropertyCount(&dwCount);
  143. if ( varPath.vt == VT_BSTR && varPath.bstrVal != NULL )
  144. {
  145. if ( ACTIONTYPE_DELETE == atAction )
  146. {
  147. hr = DeleteInstance(pHandler, &SceStore, varPath.bstrVal);
  148. }
  149. else
  150. {
  151. hr = ConstructInstance(pHandler, &SceStore, varStorePath.bstrVal, varPath.bstrVal,TRUE);
  152. }
  153. }
  154. else
  155. {
  156. //
  157. // query support
  158. //
  159. hr = ConstructInstance(pHandler, &SceStore, varStorePath.bstrVal, NULL, (dwCount == 1)? FALSE : TRUE);
  160. }
  161. }
  162. else
  163. {
  164. hr = WBEM_E_NOT_FOUND;
  165. }
  166. }
  167. }
  168. return hr;
  169. }
  170. /*
  171. Routine Description:
  172. Name:
  173. CRegistryValue::PutInst
  174. Functionality:
  175. Put an instance as instructed by WMI. Since this class implements Sce_RegistryValue,
  176. which is persistence oriented, this will cause the Sce_RegistryValue object's property
  177. information to be saved in our store.
  178. Virtual:
  179. Yes.
  180. Arguments:
  181. pInst - COM interface pointer to the WMI class (Sce_RegistryValue) object.
  182. pHandler - COM interface pointer for notifying WMI of any events.
  183. pCtx - COM interface pointer. This interface is just something we pass around.
  184. WMI may mandate it (not now) in the future. But we never construct
  185. such an interface and so, we just pass around for various WMI API's
  186. Return Value:
  187. Success: it must return success code (use SUCCEEDED to test). It is
  188. not guaranteed to return WBEM_NO_ERROR.
  189. Failure: Various errors may occurs. Any such error should indicate the failure of persisting
  190. the instance.
  191. Notes:
  192. Since GetProperty will return a success code (WBEM_S_RESET_TO_DEFAULT) when the
  193. requested property is not present, don't simply use SUCCEEDED or FAILED macros
  194. to test for the result of retrieving a property.
  195. */
  196. HRESULT
  197. CRegistryValue::PutInst (
  198. IN IWbemClassObject * pInst,
  199. IN IWbemObjectSink * pHandler,
  200. IN IWbemContext * pCtx
  201. )
  202. {
  203. HRESULT hr = WBEM_E_INVALID_PARAMETER;
  204. CComBSTR bstrRegPath;
  205. CComBSTR bstrDoublePath;
  206. CComBSTR bstrConvertPath;
  207. CComBSTR bstrValue;
  208. CSceStore SceStore;
  209. //
  210. // CScePropertyMgr helps us to access WMI object's properties
  211. // create an instance and attach the WMI object to it.
  212. // This will always succeed.
  213. //
  214. CScePropertyMgr ScePropMgr;
  215. ScePropMgr.Attach(pInst);
  216. DWORD RegType=0;
  217. DWORD dwDump;
  218. //
  219. // the use of the macro SCE_PROV_IfErrorGotoCleanup cause
  220. // a "goto CleanUp;" with hr set to the return value from
  221. // the function (macro parameter)
  222. //
  223. SCE_PROV_IfErrorGotoCleanup(ScePropMgr.GetProperty(pPath, &bstrRegPath));
  224. SCE_PROV_IfErrorGotoCleanup(ConvertToDoubleBackSlashPath(bstrRegPath, L'\\',&bstrDoublePath));
  225. //
  226. // if the property doesn't exist (NULL or empty), WBEM_S_RESET_TO_DEFAULT is returned
  227. //
  228. SCE_PROV_IfErrorGotoCleanup(ScePropMgr.GetProperty(pType, &RegType));
  229. if ( hr == WBEM_S_RESET_TO_DEFAULT)
  230. {
  231. hr = WBEM_E_ILLEGAL_NULL;
  232. goto CleanUp;
  233. }
  234. SCE_PROV_IfErrorGotoCleanup(ScePropMgr.GetProperty(pData, &bstrValue));
  235. if ( hr == WBEM_S_RESET_TO_DEFAULT)
  236. {
  237. hr = WBEM_E_ILLEGAL_NULL;
  238. goto CleanUp;
  239. }
  240. //
  241. // should validate the registry value path to see if it's supported (in sceregvl.inf)
  242. //
  243. SCE_PROV_IfErrorGotoCleanup(ValidateRegistryValue(bstrDoublePath, RegType, bstrValue ));
  244. //
  245. // convert registry path from double backslash to single backslash
  246. //
  247. SCE_PROV_IfErrorGotoCleanup(MakeSingleBackSlashPath(bstrRegPath, L'\\', &bstrConvertPath));
  248. //
  249. // Attach the WMI object instance to the store and let the store know that
  250. // it's store is given by the pStorePath property of the instance.
  251. //
  252. SceStore.SetPersistProperties(pInst, pStorePath);
  253. //
  254. // For a new .inf file. Write an empty buffer to the file
  255. // will creates the file with right header/signature/unicode format
  256. // this is harmless for existing files.
  257. // For database store, this is a no-op.
  258. //
  259. SCE_PROV_IfErrorGotoCleanup(SceStore.WriteSecurityProfileInfo(
  260. AreaBogus,
  261. (PSCE_PROFILE_INFO)&dwDump,
  262. NULL,
  263. false
  264. ) );
  265. //
  266. // now save the info to file
  267. //
  268. SCE_PROV_IfErrorGotoCleanup(SceStore.SavePropertyToStore(szRegistryValues, bstrConvertPath, RegType, L',', bstrValue));
  269. CleanUp:
  270. return hr;
  271. }
  272. //////////////////////////////////////////////////////////////////////
  273. // CRegistryValue::ConstructInstance
  274. /*
  275. Routine Description:
  276. Name:
  277. CRegistryValue::ConstructInstance
  278. Functionality:
  279. This is private function to create an instance of Sce_RegistryValue.
  280. Virtual:
  281. No.
  282. Arguments:
  283. pHandler - COM interface pointer for notifying WMI of any events.
  284. pSceStore - Pointer to our store. It must have been appropriately set up.
  285. wszLogStorePath - store path, a key property of Sce_RegistryValue class.
  286. wszGroupName - a corresponding key property of Sce_RegistryValue class.
  287. bPostFilter - Controls how WMI will be informed with pHandler->SetStatus.
  288. Return Value:
  289. Success: it must return success code (use SUCCEEDED to test). It is
  290. not guaranteed to return WBEM_NO_ERROR.
  291. Failure: Various errors may occurs. Any such error should indicate the creating the instance.
  292. Notes:
  293. */
  294. HRESULT
  295. CRegistryValue::ConstructInstance (
  296. IN IWbemObjectSink * pHandler,
  297. IN CSceStore * pSceStore,
  298. IN LPCWSTR wszLogStorePath,
  299. IN LPCWSTR wszRegPath OPTIONAL,
  300. IN BOOL bPostFilter
  301. )
  302. {
  303. //
  304. // make sure that we have a valid store
  305. //
  306. if ( pSceStore == NULL || pSceStore->GetStoreType() < SCE_INF_FORMAT ||
  307. pSceStore->GetStoreType() > SCE_JET_ANALYSIS_REQUIRED )
  308. {
  309. return WBEM_E_INVALID_PARAMETER;
  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. HRESULT hr = pSceStore->GetSecurityProfileInfo(
  318. AREA_SECURITY_POLICY,
  319. &pInfo,
  320. NULL
  321. );
  322. if (FAILED(hr))
  323. {
  324. return hr;
  325. }
  326. //
  327. // search for the registry value
  328. //
  329. DWORD iKey=0;
  330. if ( wszRegPath )
  331. {
  332. //
  333. // get the registry key
  334. //
  335. for ( iKey=0; iKey<pInfo->RegValueCount; iKey++ )
  336. {
  337. if ( pInfo->aRegValues[iKey].FullValueName == NULL )
  338. {
  339. continue;
  340. }
  341. if ( _wcsicmp(pInfo->aRegValues[iKey].FullValueName, wszRegPath) == 0 )
  342. {
  343. break;
  344. }
  345. }
  346. if ( iKey > pInfo->RegValueCount )
  347. {
  348. hr = WBEM_E_NOT_FOUND;
  349. }
  350. }
  351. //
  352. // the use of the macro SCE_PROV_IfErrorGotoCleanup cause
  353. // a "goto CleanUp;" with hr set to the return value from
  354. // the function (macro parameter)
  355. //
  356. if ( SUCCEEDED(hr) )
  357. {
  358. CComBSTR bstrLogOut;
  359. SCE_PROV_IfErrorGotoCleanup(MakeSingleBackSlashPath(wszLogStorePath, L'\\', &bstrLogOut));
  360. for (DWORD i = iKey; i < pInfo->RegValueCount; i++)
  361. {
  362. CComPtr<IWbemClassObject> srpObj;
  363. SCE_PROV_IfErrorGotoCleanup(SpawnAnInstance(&srpObj));
  364. //
  365. // CScePropertyMgr helps us to access WMI object's properties
  366. // create an instance and attach the WMI object to it.
  367. // This will always succeed.
  368. //
  369. CScePropertyMgr ScePropMgr;
  370. ScePropMgr.Attach(srpObj);
  371. SCE_PROV_IfErrorGotoCleanup(ScePropMgr.PutProperty(pStorePath, bstrLogOut));
  372. SCE_PROV_IfErrorGotoCleanup(ScePropMgr.PutProperty(pPath, pInfo->aRegValues[i].FullValueName));
  373. SCE_PROV_IfErrorGotoCleanup(ScePropMgr.PutProperty(pType, pInfo->aRegValues[i].ValueType ));
  374. if ( pInfo->aRegValues[i].Value )
  375. {
  376. SCE_PROV_IfErrorGotoCleanup(ScePropMgr.PutProperty(pData, pInfo->aRegValues[i].Value ));
  377. }
  378. //
  379. // do the necessary gestures to WMI.
  380. // the use of WBEM_STATUS_REQUIREMENTS in SetStatus is not documented by WMI
  381. // at this point. Consult WMI team for detail if you suspect problems with
  382. // the use of WBEM_STATUS_REQUIREMENTS
  383. //
  384. if ( !bPostFilter )
  385. {
  386. pHandler->SetStatus(WBEM_STATUS_REQUIREMENTS, S_FALSE, NULL, NULL);
  387. }
  388. else
  389. {
  390. pHandler->SetStatus(WBEM_STATUS_REQUIREMENTS, S_OK, NULL, NULL);
  391. }
  392. //
  393. // pass the new instance to WMI
  394. //
  395. hr = pHandler->Indicate(1, &srpObj);
  396. if ( wszRegPath )
  397. {
  398. // to get one instance only
  399. break;
  400. }
  401. }
  402. }
  403. CleanUp:
  404. pSceStore->FreeSecurityProfileInfo(pInfo);
  405. return hr;
  406. }
  407. /*
  408. Routine Description:
  409. Name:
  410. CRegistryValue::DeleteInstance
  411. Functionality:
  412. remove an instance of Sce_RegistryValue from the specified store.
  413. Virtual:
  414. No.
  415. Arguments:
  416. pHandler - COM interface pointer for notifying WMI of any events.
  417. pSceStore - Pointer to our store. It must have been appropriately set up.
  418. wszRegPath - property of the Sce_RegistryValue class.
  419. Return Value:
  420. Success: WBEM_NO_ERROR.
  421. Failure: WBEM_E_INVALID_PARAMETER.
  422. Notes:
  423. */
  424. HRESULT CRegistryValue::DeleteInstance (
  425. IN IWbemObjectSink * pHandler,
  426. IN CSceStore * pSceStore,
  427. IN LPCWSTR wszRegPath
  428. )
  429. {
  430. //
  431. // make sure that we have a valid store
  432. //
  433. if ( pSceStore == NULL || pSceStore->GetStoreType() < SCE_INF_FORMAT ||
  434. pSceStore->GetStoreType() > SCE_JET_ANALYSIS_REQUIRED )
  435. {
  436. return WBEM_E_INVALID_PARAMETER;
  437. }
  438. //
  439. // passing a NULL value will cause the property to be deleted.
  440. //
  441. return pSceStore->SavePropertyToStore(szRegistryValues, wszRegPath, (LPCWSTR)NULL);
  442. }
  443. /*
  444. Routine Description:
  445. Name:
  446. CRegistryValue::ValidateRegistryValue
  447. Functionality:
  448. Private helper. Will verify if the registry value is valid.
  449. Virtual:
  450. No.
  451. Arguments:
  452. wszRegPath - Registry value's path. A property of the Sce_RegistryValue class.
  453. bstrValue - The string value of the property. A property of the Sce_RegistryValue class.
  454. RegType - data type of the registry value. A property of the Sce_RegistryValue class.
  455. Return Value:
  456. Success: WBEM_NO_ERROR.
  457. Failure: WBEM_E_INVALID_PARAMETER.
  458. Notes:
  459. */
  460. HRESULT CRegistryValue::ValidateRegistryValue (
  461. IN BSTR bstrRegPath,
  462. IN DWORD RegType,
  463. IN BSTR bstrValue
  464. )
  465. {
  466. if ( bstrRegPath == NULL || bstrValue == NULL )
  467. {
  468. return WBEM_E_INVALID_PARAMETER;
  469. }
  470. DWORD Len = SysStringLen(bstrRegPath);
  471. LPCWSTR pQuery = L"SELECT * FROM Sce_KnownRegistryValues WHERE PathName=\"";
  472. //
  473. // memory allocated for the bstrQueryCategories will be automatically released by CComBSTR
  474. //
  475. CComBSTR bstrQueryCategories;
  476. //
  477. // 1 for closing quote and 1 for 0 terminator
  478. //
  479. bstrQueryCategories.m_str = ::SysAllocStringLen(NULL, Len + wcslen(pQuery) + 2);
  480. if ( bstrQueryCategories.m_str == NULL )
  481. {
  482. return WBEM_E_OUT_OF_MEMORY;
  483. }
  484. //
  485. // this won't overrun. See allocation size above
  486. //
  487. wcscpy(bstrQueryCategories.m_str, pQuery);
  488. wcscat(bstrQueryCategories.m_str, bstrRegPath);
  489. wcscat(bstrQueryCategories.m_str, L"\"");
  490. HRESULT hr;
  491. CComPtr<IEnumWbemClassObject> srpEnum;
  492. CComPtr<IWbemClassObject> srpObj;
  493. ULONG n = 0;
  494. //
  495. // query all registry values of this path name
  496. //
  497. hr = m_srpNamespace->ExecQuery(L"WQL",
  498. bstrQueryCategories,
  499. WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY,
  500. NULL,
  501. &srpEnum
  502. );
  503. if (SUCCEEDED(hr))
  504. {
  505. //
  506. // should get one and only one instance
  507. //
  508. hr = srpEnum->Next(WBEM_INFINITE, 1, &srpObj, &n);
  509. if ( hr == WBEM_S_FALSE )
  510. {
  511. //
  512. // not find any
  513. //
  514. hr = WBEM_E_INVALID_PARAMETER;
  515. }
  516. if (SUCCEEDED(hr))
  517. {
  518. if (n > 0)
  519. {
  520. //
  521. // find the instance
  522. //
  523. DWORD dwValue = 0;
  524. //
  525. // CScePropertyMgr helps us to access WMI object's properties
  526. // create an instance and attach the WMI object to it.
  527. // This will always succeed.
  528. //
  529. CScePropertyMgr ScePropMgr;
  530. ScePropMgr.Attach(srpObj);
  531. hr = ScePropMgr.GetProperty(pType, &dwValue);
  532. if ( SUCCEEDED(hr) )
  533. {
  534. if ( hr != WBEM_S_RESET_TO_DEFAULT && (DWORD)dwValue == RegType )
  535. {
  536. hr = WBEM_S_NO_ERROR;
  537. }
  538. else
  539. {
  540. hr = WBEM_E_INVALID_PARAMETER;
  541. }
  542. }
  543. }
  544. else
  545. {
  546. hr = WBEM_E_INVALID_PARAMETER;
  547. }
  548. }
  549. }
  550. return hr;
  551. }