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.

1321 lines
37 KiB

  1. // File: regzone.cxx
  2. //
  3. // Contents: Registry management for a single zone.
  4. //
  5. // Classes: CRegZone
  6. //
  7. // Functions:
  8. //
  9. // History:
  10. //
  11. //----------------------------------------------------------------------------
  12. #include "zonepch.h"
  13. // Max # of chars to the root of the zones tree (SZZONES, SZTEMPLATE,...)
  14. #define MAX_REGZONE_ROOT 100
  15. // Value names in the registry
  16. #define SZZONEINDEX __TEXT("ZoneIndex")
  17. #define SZTEMPLATEINDEX __TEXT("TemplateIndex")
  18. #define SZDISPLAYNAME __TEXT("DisplayName")
  19. #define SZICON __TEXT("Icon")
  20. #define SZDESCRIPTION __TEXT("Description")
  21. #define SZFLAGS __TEXT("Flags")
  22. // Registry key names for the template policies
  23. #define SZLOW __TEXT("Low")
  24. #define SZMEDLOW __TEXT("MedLow")
  25. #define SZMEDIUM __TEXT("Medium")
  26. #define SZHIGH __TEXT("High")
  27. CRegZone::CRegZoneCache CRegZone::s_rzcache;
  28. HANDLE CRegZone::CRegZoneCache::s_hMutexCounter;
  29. // Array of Value Names corresponding to zone attributes.
  30. // These values will not be copied when doing a mass copy
  31. // from a template zone (HIGH, MED, LOW) to a zone.
  32. static LPCTSTR rgszAttributeNames [ ] =
  33. {
  34. __TEXT(""), // The default value is excluded as well.
  35. SZZONEINDEX,
  36. SZTEMPLATEINDEX,
  37. SZDISPLAYNAME,
  38. SZDESCRIPTION,
  39. SZICON,
  40. SZFLAGS,
  41. SZMINLEVEL,
  42. SZRECLEVEL,
  43. SZCURRLEVEL,
  44. };
  45. struct templateNameIdxMap
  46. {
  47. URLTEMPLATE index;
  48. LPCTSTR pszName;
  49. };
  50. static templateNameIdxMap
  51. TemplateNameIdxMap [ ] =
  52. {
  53. { URLTEMPLATE_LOW, SZLOW },
  54. { URLTEMPLATE_MEDLOW, SZMEDLOW},
  55. { URLTEMPLATE_MEDIUM, SZMEDIUM},
  56. { URLTEMPLATE_HIGH, SZHIGH}
  57. };
  58. // CRegZone implementation.
  59. CRegZone::CRegZone()
  60. {
  61. // defaults
  62. m_dwZoneId = ZONEID_INVALID;
  63. m_dwZoneFlags = ZAFLAGS_ADD_SITES; // BUGBUG: what is the right default here.
  64. m_lpZoneName = NULL;
  65. m_lpZonePath = NULL;
  66. m_bStandard = TRUE;
  67. m_bZoneLockOut = FALSE;
  68. m_bHKLMOnly = TRUE;
  69. }
  70. CRegZone::~CRegZone()
  71. {
  72. LocalFree((HLOCAL)m_lpZoneName);
  73. LocalFree((HLOCAL)m_lpZonePath);
  74. }
  75. // Sets up the CRegZone object a given string.
  76. // If the setting is in the Zones key the string passed in is the actual
  77. // zone index. Otherwise it is one of the "High", "Medium", "Low" strings which indicates
  78. // a template policy.
  79. BOOL CRegZone::Init(LPCWSTR lpwStr, BOOL bUseHKLMOnly, REGZONEUSE regZoneUse, BOOL bCreate /*=TRUE*/)
  80. {
  81. TransAssert(lpwStr != NULL);
  82. if (lpwStr == NULL)
  83. {
  84. return FALSE;
  85. }
  86. m_bHKLMOnly = bUseHKLMOnly;
  87. m_regZoneUse = regZoneUse;
  88. TCHAR szTemp[MAX_REGZONE_ROOT + MAX_ZONE_NAME];
  89. StrCpyW(szTemp, (regZoneUse == REGZONEUSEZONES? SZZONES : SZTEMPLATE));
  90. StrCatW(szTemp, lpwStr);
  91. m_lpZonePath = StrDup(szTemp);
  92. if(!m_lpZonePath)
  93. {
  94. return FALSE;
  95. }
  96. m_lpZoneName = StrDup(lpwStr);
  97. if(!m_lpZoneName)
  98. {
  99. return FALSE;
  100. }
  101. CRegKey regKey(bUseHKLMOnly);
  102. if (regKey.Open(NULL, m_lpZonePath, KEY_READ) != ERROR_SUCCESS)
  103. {
  104. // BUGBUG:: We have to be able to deal with this. situation and not just bail.
  105. // Possibilities: Setup defaults here if we can create and write to the key
  106. return FALSE;
  107. }
  108. // Add code here to
  109. DWORD dwZoneId = ZONEID_INVALID;
  110. // Get the Zone Index.
  111. if ( regZoneUse == REGZONEUSEZONES )
  112. {
  113. // The Zone Id for the string is the same as the key name.
  114. // Just convert the string
  115. m_dwZoneId = StrToInt(m_lpZoneName);
  116. }
  117. else if (regZoneUse == REGZONEUSETEMPLATE )
  118. {
  119. if (regKey.QueryValue(&dwZoneId, SZTEMPLATEINDEX) == ERROR_SUCCESS)
  120. m_dwZoneId = dwZoneId;
  121. else
  122. {
  123. // Could happen if the registry is messed up.
  124. TransAssert(FALSE);
  125. }
  126. }
  127. else
  128. {
  129. TransAssert(FALSE);
  130. }
  131. // Get the zone flags
  132. if (regKey.QueryValue(&m_dwZoneFlags, SZFLAGS) != ERROR_SUCCESS)
  133. {
  134. m_dwZoneFlags = ZAFLAGS_ADD_SITES; // What is the right value here.
  135. }
  136. else
  137. {
  138. // return value from UpdateZoneMapFlags ignored.
  139. UpdateZoneMapFlags( );
  140. }
  141. // Check and make sure the zone Id's are within range.
  142. // Assert that the zone ID's are in the appropriate user or standard range.
  143. return TRUE;
  144. }
  145. // This updates the flags in the ZoneMap part of the registry which correspond to the
  146. // ZAFLAGS_. For convenience the UI will only update the ZAFLAGS.
  147. BOOL CRegZone::UpdateZoneMapFlags( )
  148. {
  149. // ProxyByPass is current controlled by the ProxyByPass flag, not the zoneAttrib.
  150. if (m_dwZoneId == URLZONE_INTRANET)
  151. {
  152. // If we are updating zonemap flags we have to invalidate any url to zone caches
  153. CSecurityManager::IncrementGlobalCounter( );
  154. CRegKey regZoneMap;
  155. if (ERROR_SUCCESS == regZoneMap.Open(NULL, SZZONEMAP, KEY_READ | KEY_WRITE))
  156. {
  157. if (m_dwZoneFlags & ZAFLAGS_INCLUDE_PROXY_OVERRIDE)
  158. {
  159. // We will succeed even if this fails.
  160. regZoneMap.SetValue(m_dwZoneId, SZPROXYBYPASS);
  161. }
  162. else
  163. {
  164. regZoneMap.DeleteValue(SZPROXYBYPASS);
  165. }
  166. if (m_dwZoneFlags & ZAFLAGS_INCLUDE_INTRANET_SITES)
  167. {
  168. // We will succeed even if this fails.
  169. regZoneMap.SetValue(m_dwZoneId, SZINTRANETNAME);
  170. }
  171. else
  172. {
  173. regZoneMap.DeleteValue(SZINTRANETNAME);
  174. }
  175. DWORD dwUncAsIntranet = (m_dwZoneFlags & ZAFLAGS_UNC_AS_INTRANET) ? 1 : 0 ;
  176. regZoneMap.SetValue(dwUncAsIntranet, SZUNCASINTRANET);
  177. }
  178. }
  179. return TRUE;
  180. }
  181. // Static functions.
  182. VOID
  183. CRegZone::IncrementGlobalCounter( )
  184. {
  185. CRegZone::CRegZoneCache::IncrementGlobalCounter( );
  186. }
  187. BOOL CRegZone::IsAttributeName(LPCTSTR psz)
  188. {
  189. DWORD dwMaxIndex = sizeof(rgszAttributeNames)/sizeof(rgszAttributeNames[0]);
  190. for ( DWORD dwIndex = 0 ; dwIndex < dwMaxIndex ; dwIndex++ )
  191. {
  192. #ifndef UNIX
  193. if (0 == StrCmpW(psz, rgszAttributeNames[dwIndex]))
  194. #else
  195. if (0 == lstrcmpi(psz, rgszAttributeNames[dwIndex]))
  196. #endif
  197. return TRUE;
  198. }
  199. return FALSE;
  200. }
  201. LPCTSTR CRegZone::GetTemplateNameFromIndex(URLTEMPLATE urlTemplateIndex)
  202. {
  203. DWORD dwMaxIndex = sizeof(TemplateNameIdxMap) / sizeof(TemplateNameIdxMap[0]);
  204. for (DWORD dwIndex = 0 ; dwIndex < dwMaxIndex ; dwIndex++ )
  205. {
  206. if (TemplateNameIdxMap[dwIndex].index == urlTemplateIndex)
  207. return TemplateNameIdxMap[dwIndex].pszName;
  208. }
  209. return NULL;
  210. }
  211. // These are static functions to deal with aggregate policies.
  212. // Because of the discrepancy between the UI and the actions defined,
  213. // there are cases where the security manager munges the policies for certain actions.
  214. inline void CRegZone::KludgeMapAggregatePolicy(DWORD dwAction, LPDWORD pdwPolicy)
  215. {
  216. TransAssert(pdwPolicy != NULL);
  217. switch (dwAction)
  218. {
  219. case URLACTION_ACTIVEX_OVERRIDE_DATA_SAFETY:
  220. case URLACTION_ACTIVEX_OVERRIDE_SCRIPT_SAFETY:
  221. case URLACTION_SCRIPT_OVERRIDE_SAFETY:
  222. {
  223. if (GetUrlPolicyPermissions(*pdwPolicy) == URLPOLICY_QUERY)
  224. SetUrlPolicyPermissions(*pdwPolicy, URLPOLICY_DISALLOW);
  225. break;
  226. }
  227. }
  228. }
  229. // Call this function to determine if an action is aggregated by some
  230. // other action.
  231. // RETURNS : TRUE if there is an aggregate action corr to dwAction.
  232. // also returns the action in pdwAggregate.
  233. // FALSE: if this action is not aggregated by some other action.
  234. // pdwAggregate is unchanged in this case.
  235. inline BOOL CRegZone::GetAggregateAction(DWORD dwAction, LPDWORD pdwAggregate)
  236. {
  237. DWORD dwAggregate = 0;
  238. BOOL bReturn = FALSE;
  239. TransAssert(dwAction >= URLACTION_MIN);
  240. switch(dwAction)
  241. {
  242. case URLACTION_ACTIVEX_OVERRIDE_DATA_SAFETY:
  243. case URLACTION_ACTIVEX_OVERRIDE_SCRIPT_SAFETY:
  244. case URLACTION_ACTIVEX_CONFIRM_NOOBJECTSAFETY:
  245. case URLACTION_SCRIPT_OVERRIDE_SAFETY:
  246. bReturn = TRUE;
  247. dwAggregate = URLACTION_ACTIVEX_OVERRIDE_OBJECT_SAFETY;
  248. break;
  249. case URLACTION_HTML_SUBMIT_FORMS_FROM:
  250. case URLACTION_HTML_SUBMIT_FORMS_TO:
  251. bReturn = TRUE;
  252. dwAggregate = URLACTION_HTML_SUBMIT_FORMS;
  253. break;
  254. }
  255. if (bReturn && pdwAggregate)
  256. *pdwAggregate = dwAggregate;
  257. return bReturn;
  258. }
  259. // Functions corresponding to IInternetZoneManager functionality.
  260. STDMETHODIMP CRegZone::GetZoneAttributes(ZONEATTRIBUTES& zoneAttrib)
  261. {
  262. if (!IsValid())
  263. {
  264. return E_FAIL;
  265. }
  266. CRegKey regKey(m_bHKLMOnly);
  267. if (regKey.Open(NULL, m_lpZonePath, KEY_READ) != ERROR_SUCCESS)
  268. {
  269. // BUGBUG:: We have to be able to deal with this. situation and not just bail.
  270. // Possibilities: Setup defaults here if we can create and write to the key
  271. return E_FAIL;
  272. }
  273. // Since this is the first rev, we should have enough memory
  274. // to fill in the ZONEATTRIBUTES structure. If we need to extend
  275. // the structure this code will have to be modified.
  276. TransAssert(zoneAttrib.cbSize >= sizeof(ZONEATTRIBUTES));
  277. // Amount of information we will copy.
  278. zoneAttrib.cbSize = sizeof(ZONEATTRIBUTES);
  279. TransAssert(regKey!= NULL);
  280. DWORD dwCount;
  281. LONG lRet;
  282. // BUGBUG deal with values exceeding size limit.
  283. // We would have to allocate memory ourself and
  284. // truncate the resulting string down.
  285. // Read DisplayName.
  286. dwCount = sizeof(zoneAttrib.szDisplayName);
  287. lRet = regKey.QueryValue(zoneAttrib.szDisplayName, SZDISPLAYNAME, &dwCount);
  288. TransAssert(ERROR_MORE_DATA != lRet);
  289. if (NO_ERROR != lRet)
  290. zoneAttrib.szDisplayName[0] = __TEXT('\0');
  291. // Read Description
  292. dwCount = sizeof(zoneAttrib.szDescription);
  293. regKey.QueryValue(zoneAttrib.szDescription, SZDESCRIPTION, &dwCount);
  294. TransAssert(ERROR_MORE_DATA != lRet);
  295. if (NO_ERROR != lRet)
  296. zoneAttrib.szDescription[0] = __TEXT('\0');
  297. // Read Icon.
  298. dwCount = sizeof(zoneAttrib.szIconPath);
  299. regKey.QueryValue(zoneAttrib.szIconPath, SZICON, &dwCount);
  300. TransAssert(ERROR_MORE_DATA != lRet);
  301. if (NO_ERROR != lRet)
  302. zoneAttrib.szIconPath[0] = __TEXT('\0');
  303. // Read Current, Recommended and Min Settings.
  304. QueryTemplatePolicyIndex(regKey, SZMINLEVEL, &zoneAttrib.dwTemplateMinLevel);
  305. QueryTemplatePolicyIndex(regKey, SZRECLEVEL, &zoneAttrib.dwTemplateRecommended);
  306. QueryTemplatePolicyIndex(regKey, SZCURRLEVEL, &zoneAttrib.dwTemplateCurrentLevel);
  307. // Re-read the flags in case someone else updated it in an independent process.
  308. DWORD dwZoneFlags;
  309. if (regKey.QueryValue(&dwZoneFlags, SZFLAGS) == ERROR_SUCCESS)
  310. {
  311. m_dwZoneFlags = dwZoneFlags;
  312. UpdateZoneMapFlags();
  313. }
  314. zoneAttrib.dwFlags = m_dwZoneFlags;
  315. return S_OK;
  316. }
  317. STDMETHODIMP CRegZone::SetZoneAttributes(const ZONEATTRIBUTES& zoneAttrib)
  318. {
  319. if (!IsValid())
  320. {
  321. return E_FAIL;
  322. }
  323. // Check if the attributes we are trying to set are valid.
  324. if (!IsValidTemplateIndex(zoneAttrib.dwTemplateMinLevel) ||
  325. !IsValidTemplateIndex(zoneAttrib.dwTemplateCurrentLevel) ||
  326. !IsValidTemplateIndex(zoneAttrib.dwTemplateRecommended))
  327. {
  328. return E_INVALIDARG;
  329. }
  330. CRegKey regKey(m_bHKLMOnly);
  331. if (regKey.Open(NULL, m_lpZonePath, KEY_WRITE | KEY_READ) != ERROR_SUCCESS)
  332. {
  333. // BUGBUG:: We have to be able to deal with this. situation and not just bail.
  334. // Possibilities: Setup defaults here if we can create and write to the key
  335. return E_FAIL;
  336. }
  337. // Write the descriptive strings.
  338. // These should almost never be changed by this call.
  339. if (zoneAttrib.szDisplayName[0] != TEXT('\0'))
  340. regKey.SetValue(zoneAttrib.szDisplayName, SZDISPLAYNAME);
  341. if (zoneAttrib.szDescription[0] != TEXT('\0'))
  342. regKey.SetValue(zoneAttrib.szDescription, SZDESCRIPTION);
  343. if (zoneAttrib.szIconPath[0] != TEXT('\0'))
  344. regKey.SetValue(zoneAttrib.szIconPath, SZICON);
  345. // Write the Template Indicies.
  346. SetTemplatePolicyIndex(regKey, SZMINLEVEL, zoneAttrib.dwTemplateMinLevel);
  347. SetTemplatePolicyIndex(regKey, SZRECLEVEL, zoneAttrib.dwTemplateRecommended);
  348. DWORD dwTemplateCurrentLevel;
  349. // When the caller is setting the "CurrentLevel" to "Custom" it is assumed
  350. // that the caller has already changed the underlying policies.
  351. if (zoneAttrib.dwTemplateCurrentLevel == URLTEMPLATE_CUSTOM)
  352. {
  353. SetTemplatePolicyIndex(regKey, SZCURRLEVEL, zoneAttrib.dwTemplateCurrentLevel);
  354. }
  355. else
  356. {
  357. CopyTemplatePolicies(zoneAttrib.dwTemplateCurrentLevel);
  358. }
  359. // Finally write the flags value.
  360. regKey.SetValue(zoneAttrib.dwFlags, SZFLAGS);
  361. m_dwZoneFlags = zoneAttrib.dwFlags;
  362. UpdateZoneMapFlags();
  363. IncrementGlobalCounter(); // increment the count to invalidate the zone policy cache
  364. return S_OK;
  365. }
  366. STDMETHODIMP CRegZone::GetActionPolicy(DWORD dwAction, URLZONEREG urlZoneReg, DWORD& dwPolicy) const
  367. {
  368. if (!IsValid())
  369. return E_FAIL;
  370. DWORD dwActionUse;
  371. // If the action is aggregated by some other action, then we should
  372. // actually check the policy for the aggregate action. If the function
  373. if (!GetAggregateAction(dwAction, &dwActionUse))
  374. dwActionUse = dwAction;
  375. // If it is a hard-coded zone get the policy from internal tables.
  376. // Don't look up the registry for these.
  377. if (IsHardCodedZone() && GetHardCodedZonePolicy(dwActionUse, dwPolicy))
  378. {
  379. // dwPolicy should have the policy now.
  380. }
  381. else
  382. {
  383. if(!s_rzcache.Lookup(m_dwZoneId, m_lpZonePath, dwActionUse, UseHKLM(urlZoneReg), &dwPolicy))
  384. {
  385. return E_FAIL;
  386. }
  387. // For some special aggregate policies we have to modify the policy value.
  388. KludgeMapAggregatePolicy(dwAction, &dwPolicy);
  389. }
  390. return S_OK;
  391. }
  392. STDMETHODIMP CRegZone::SetActionPolicy(DWORD dwAction, URLZONEREG urlZoneReg, DWORD dwPolicy)
  393. {
  394. if (!IsValid())
  395. return E_FAIL;
  396. CRegKey regKey(UseHKLM(urlZoneReg));
  397. if (regKey.Open(NULL, m_lpZonePath, KEY_WRITE) != ERROR_SUCCESS)
  398. {
  399. // BUGBUG:: We have to be able to deal with this. situation and not just bail.
  400. // Possibilities: Setup defaults here if we can create and write to the key
  401. return E_FAIL;
  402. }
  403. // Policies cannot be set on Actions that are aggregate's.
  404. // They can be only be set on the aggregator policy.
  405. if (IsHardCodedZone())
  406. {
  407. TransAssert(FALSE);
  408. return E_FAIL;
  409. }
  410. DWORD dwActionUse;
  411. // If the action is aggregated by some other action, then we should
  412. // actually use the policy for the aggregate action.
  413. if (!GetAggregateAction(dwAction, &dwActionUse))
  414. dwActionUse = dwAction;
  415. // Convert the Action to a string.
  416. #ifndef unix
  417. TCHAR wsz[9]; // FFFFFFFF\0
  418. #else
  419. TCHAR wsz[(sizeof(DWORD)+1)*sizeof(WCHAR)];
  420. #endif /* unix */
  421. if (!DwToWchar(dwActionUse, wsz, 16))
  422. {
  423. TransAssert(FALSE);
  424. return E_UNEXPECTED;
  425. }
  426. DWORD dwPolicyOld;
  427. if(!s_rzcache.Lookup(m_dwZoneId, m_lpZonePath, dwActionUse, UseHKLM(urlZoneReg), &dwPolicyOld) || dwPolicyOld != dwPolicy)
  428. {
  429. regKey.SetValue(dwPolicy, wsz);
  430. s_rzcache.Add(m_dwZoneId, dwActionUse, UseHKLM(urlZoneReg), dwPolicy, URLZONE_FINDCACHEENTRY);
  431. // We have to reset the "CurrentLevel" to "Custom" because we have changed an underlying policy:
  432. SetTemplatePolicyIndex(regKey, SZCURRLEVEL, URLTEMPLATE_CUSTOM);
  433. }
  434. return S_OK;
  435. }
  436. STDMETHODIMP CRegZone::GetCustomPolicy (REFGUID guid, URLZONEREG urlZoneReg, BYTE** ppByte, DWORD *pcb) const
  437. {
  438. if (!IsValid())
  439. return E_FAIL;
  440. CRegKey regKey(UseHKLM(urlZoneReg));
  441. if (regKey.Open(NULL, m_lpZonePath, KEY_READ) != ERROR_SUCCESS)
  442. {
  443. // BUGBUG:: We have to be able to deal with this. situation and not just bail.
  444. // Possibilities: Setup defaults here if we can create and write to the key
  445. return E_FAIL;
  446. }
  447. // Convert the Action to a string.
  448. TCHAR sz[40]; // {8CC49940-3146-11CF-97A1-00AA00424A9F}\0
  449. SHStringFromGUID(guid, sz, sizeof(sz));
  450. *pcb = 0;
  451. // First figure out the amount of memory required.
  452. if (regKey.QueryBinaryValue(NULL, sz, pcb) != ERROR_SUCCESS)
  453. {
  454. return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
  455. }
  456. // Memory will be freed by caller.
  457. *ppByte = (BYTE *)CoTaskMemAlloc(*pcb);
  458. if ( *ppByte == NULL)
  459. {
  460. return E_OUTOFMEMORY;
  461. }
  462. // Actually query the registry for the value.
  463. if (regKey.QueryBinaryValue(*ppByte, sz, pcb) != ERROR_SUCCESS)
  464. {
  465. return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
  466. }
  467. return S_OK;
  468. }
  469. STDMETHODIMP CRegZone::SetCustomPolicy (REFGUID guid, URLZONEREG urlZoneReg, BYTE* pByte, DWORD cb)
  470. {
  471. if (!IsValid())
  472. return E_FAIL;
  473. CRegKey regKey(UseHKLM(urlZoneReg));
  474. if (regKey.Open(NULL, m_lpZonePath, KEY_WRITE) != ERROR_SUCCESS)
  475. {
  476. // BUGBUG:: We have to be able to deal with this. situation and not just bail.
  477. // Possibilities: Setup defaults here if we can create and write to the key
  478. return E_FAIL;
  479. }
  480. // Convert the Action to a string.
  481. TCHAR sz[40]; // {8CC49940-3146-11CF-97A1-00AA00424A9F}\0
  482. SHStringFromGUID(guid, sz, sizeof(sz));
  483. DWORD dwError = ERROR_SUCCESS;
  484. if ((dwError = regKey.SetBinaryValue(pByte, sz, cb)) != ERROR_SUCCESS)
  485. {
  486. return HRESULT_FROM_WIN32(dwError);
  487. }
  488. return S_OK;
  489. }
  490. STDMETHODIMP CRegZone::CopyTemplatePolicies(DWORD dwTemplate)
  491. // Copy the policies from a predefined template into the current zone
  492. {
  493. HRESULT hr = E_FAIL;
  494. // First check if we can get a name back for the template.
  495. LPCTSTR szTemplateName = GetTemplateNameFromIndex((URLTEMPLATE)dwTemplate);
  496. if (NULL == szTemplateName )
  497. return E_INVALIDARG;
  498. // Create a CRegZone for the template.
  499. CRegZone regTemplate;
  500. if (regTemplate.Init(szTemplateName, TRUE /* templates are stored in HKLM only */, REGZONEUSETEMPLATE))
  501. {
  502. CRegKey regZoneKey(m_bHKLMOnly);
  503. CRegKey regTemplateKey(TRUE);
  504. if ((NO_ERROR == regTemplateKey.Open(NULL, regTemplate.m_lpZonePath, KEY_READ)) &&
  505. (NO_ERROR == regZoneKey.Open(NULL, m_lpZonePath, KEY_WRITE)))
  506. {
  507. TCHAR szValueName[MAX_VALUE_NAME];
  508. DWORD dwNameLen = sizeof(szValueName)/sizeof(TCHAR);
  509. DWORD dwBufLen = 2048;
  510. DWORD dwActualLen = 2048;
  511. BYTE * buffer = new BYTE[dwBufLen];
  512. DWORD dwEnumIndex = 0;
  513. DWORD dwType;
  514. LONG lRet;
  515. while ((lRet = regTemplateKey.EnumValue (dwEnumIndex, szValueName, &dwNameLen, &dwType, buffer, &dwActualLen))
  516. != ERROR_NO_MORE_ITEMS)
  517. {
  518. // Need more memory, allocate and re-try.
  519. if (lRet == ERROR_MORE_DATA && dwActualLen > dwBufLen)
  520. {
  521. dwBufLen = dwActualLen;
  522. delete [] buffer;
  523. buffer = new BYTE[dwBufLen];
  524. dwNameLen = sizeof(szValueName)/sizeof(TCHAR);
  525. // Try with the bigger buffer.
  526. lRet = regTemplateKey.EnumValue(dwEnumIndex, szValueName, &dwNameLen, &dwType, buffer, &dwActualLen);
  527. }
  528. // dwActualLen contains the actual size of the data to be written.
  529. if (lRet == NO_ERROR && !IsAttributeName(szValueName))
  530. {
  531. // Copy the value over.
  532. regZoneKey.SetValueOfType(buffer, szValueName, dwActualLen, dwType);
  533. }
  534. dwEnumIndex++;
  535. dwActualLen = dwBufLen;
  536. dwNameLen = sizeof(szValueName)/sizeof(TCHAR);
  537. }
  538. // Set the "CurrentLevel" value to the Template Index.
  539. if (regZoneKey.SetValue(dwTemplate, SZCURRLEVEL) == NO_ERROR)
  540. hr = S_OK;
  541. delete [] buffer;
  542. }
  543. }
  544. return hr;
  545. }
  546. // CRegZoneContainer methods.
  547. CRegZoneContainer::CRegZoneContainer()
  548. {
  549. m_ppRegZones = NULL;
  550. m_cZones = 0;
  551. m_bHKLMOnly = FALSE;
  552. m_pZoneEnumList = NULL;
  553. m_dwNextEnum = 0;
  554. InitializeCriticalSection(&m_csect);
  555. }
  556. CRegZoneContainer::~CRegZoneContainer()
  557. {
  558. Detach();
  559. DeleteCriticalSection(&m_csect);
  560. };
  561. // This functions goes through the registry and creates the CRegZone objects corresponding
  562. // to the zones currently in the registry.
  563. BOOL CRegZoneContainer::Attach(BOOL bUseHKLM, REGZONEUSE regZoneUse /* = REGZONEUSEZONES */)
  564. {
  565. // If this assert fires you probably forgot to call Detach.
  566. TransAssert(m_cZones == 0);
  567. TransAssert(m_ppRegZones == NULL);
  568. // recover if we are messed up.
  569. Detach();
  570. m_bHKLMOnly = bUseHKLM ;
  571. TCHAR sz[MAX_REGZONE_ROOT];
  572. StrCpyW(sz, (regZoneUse == REGZONEUSEZONES ? SZZONES : SZTEMPLATE ));
  573. // Make sure we have the minimal set of zones required and we self-heal if there is a problem.
  574. // even if self-heal fails we ignore the error code and try to initialize the zones anyway.
  575. if (regZoneUse == REGZONEUSEZONES )
  576. SelfHeal(bUseHKLM);
  577. CRegKey regKey(m_bHKLMOnly);
  578. if (regKey.Open(NULL, sz, KEY_READ) != ERROR_SUCCESS)
  579. {
  580. // Hosed setup right defaults here.
  581. return FALSE;
  582. }
  583. TransAssert(regKey.m_hKey != NULL);
  584. // For each entry in the registry
  585. DWORD dwIndex = 0;
  586. DWORD dwCount = 0;
  587. DWORD lRes;
  588. TCHAR szZoneName[MAX_ZONE_NAME];
  589. DWORD dwSize = MAX_ZONE_NAME;
  590. CRegListElem *pElemStart = NULL;
  591. for (; (lRes = regKey.EnumKey(dwIndex, szZoneName, &dwSize)) != ERROR_NO_MORE_ITEMS; dwIndex++)
  592. {
  593. if (lRes != ERROR_SUCCESS)
  594. {
  595. break;
  596. }
  597. dwSize = MAX_ZONE_NAME;
  598. CRegZone *pRegZone = new CRegZone();
  599. if (pRegZone == NULL)
  600. {
  601. m_cZones = 0;
  602. // Out of memory -- change all error codes to return HRESULT's
  603. break;
  604. }
  605. if (!pRegZone->Init(szZoneName, m_bHKLMOnly))
  606. {
  607. continue; // can't create the zone for some reason.
  608. }
  609. m_cZones++;
  610. CRegListElem * pRegListElem = new CRegListElem();
  611. if ( pRegListElem == NULL)
  612. {
  613. m_cZones = 0;
  614. break; // Out of memory.
  615. }
  616. pRegListElem->pRegZone = pRegZone;
  617. pRegListElem->dwZoneIndex = pRegZone->GetZoneId();
  618. // Insert list into sorted position.
  619. if (pElemStart == NULL)
  620. {
  621. pElemStart = pRegListElem;
  622. pRegListElem->next = NULL;
  623. }
  624. else if (pElemStart->dwZoneIndex > pRegListElem->dwZoneIndex)
  625. {
  626. // Insert to the head of the list.
  627. pRegListElem->next = pElemStart;
  628. pElemStart = pRegListElem;
  629. }
  630. else
  631. {
  632. // Insert in the correct position.
  633. CRegListElem *pElemCurr = pElemStart;
  634. while (pElemCurr->next != NULL &&
  635. pElemCurr->next->dwZoneIndex < pRegListElem->dwZoneIndex )
  636. {
  637. pElemCurr = pElemCurr->next;
  638. }
  639. TransAssert(pElemCurr != NULL);
  640. pRegListElem->next = pElemCurr->next;
  641. pElemCurr->next = pRegListElem;
  642. }
  643. }
  644. // Now that we have all the RegZones collected we will just store them in
  645. // sorted order in an array.
  646. if (m_cZones)
  647. m_ppRegZones = new LPREGZONE[m_cZones];
  648. else
  649. m_ppRegZones = NULL;
  650. if (m_ppRegZones == NULL)
  651. {
  652. // Out of memory
  653. m_cZones = 0;
  654. return FALSE;
  655. }
  656. for (dwIndex = 0; dwIndex < m_cZones ; dwIndex++)
  657. {
  658. TransAssert(pElemStart != NULL);
  659. m_ppRegZones[dwIndex] = pElemStart->pRegZone;
  660. CRegListElem * pElemDelete = pElemStart;
  661. pElemStart = pElemStart->next;
  662. delete pElemDelete;
  663. }
  664. return TRUE;
  665. }
  666. BOOL CRegZoneContainer::Detach()
  667. {
  668. // First free all the CRegZone entries we are holding on to.
  669. DWORD dwIndex = 0;
  670. for (; dwIndex < m_cZones; dwIndex++)
  671. {
  672. delete m_ppRegZones[dwIndex];
  673. }
  674. delete [] m_ppRegZones;
  675. m_ppRegZones = NULL;
  676. m_cZones = 0;
  677. m_bHKLMOnly = TRUE;
  678. // Zone enumerator cleanup.
  679. // This ASSERT will fire if you forget to call DestroyZoneEnumerator before
  680. // freeing the object.
  681. TransAssert(m_pZoneEnumList == NULL);
  682. CZoneEnumList * pNextEnum = m_pZoneEnumList;
  683. while (pNextEnum != NULL)
  684. {
  685. CZoneEnumList * pEnumListDelete = pNextEnum;
  686. pNextEnum = pNextEnum->next;
  687. delete pEnumListDelete;
  688. }
  689. return TRUE;
  690. }
  691. // This function makes sure that the minimal set of zones are in the registry If things are missing
  692. // it calls the self-registration entry point and re-creates the zone key.
  693. #define WIN2KSETUP TEXT("System\\Setup")
  694. #define INPROGRESS TEXT("SystemSetupInProgress")
  695. BOOL CRegZoneContainer::SelfHeal(BOOL bUseHKLM)
  696. {
  697. HKEY hKeyZones = NULL;
  698. if (IsInGUIModeSetup())
  699. {
  700. // ignore SelfHeal if we're in GUI-mode setup
  701. return TRUE;
  702. }
  703. if (RegOpenKeyEx((bUseHKLM ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER), SZZONES, 0, KEY_READ, &hKeyZones)
  704. == ERROR_SUCCESS)
  705. {
  706. // Strings corresponding to the five pre-defined zones.
  707. TCHAR * rgszZones[] = { TEXT("0"), TEXT("1"), TEXT("2"), TEXT("3"), TEXT("4") };
  708. int i;
  709. for (i = 0 ; i < ARRAYSIZE(rgszZones) ; i++ )
  710. {
  711. HKEY hKey;
  712. DWORD dwError = RegOpenKeyEx(hKeyZones, rgszZones[i], 0, KEY_READ, &hKey);
  713. if (dwError != ERROR_SUCCESS)
  714. break;
  715. else
  716. RegCloseKey(hKey);
  717. }
  718. RegCloseKey(hKeyZones);
  719. // If we succesfully opened all the zones.
  720. if (i == ARRAYSIZE(rgszZones))
  721. {
  722. return TRUE;
  723. }
  724. }
  725. // If we reached here we were not able to open atleast one of the keys.
  726. // Note that we use L"" because ZonesDllInstall takes a LPCWSTR
  727. BOOL bRet;
  728. HRESULT hr = ZonesDllInstall(TRUE, bUseHKLM ? L"HKLM" : L"HKCU");
  729. if (SUCCEEDED(hr))
  730. {
  731. CRegKey regKey(bUseHKLM);
  732. // Keep track of how many times we self heal for diagnostic purposes..
  733. DWORD dwSelfHealCount;
  734. TCHAR *pszSelfHealCount = TEXT("SelfHealCount");
  735. if (regKey.Open(NULL, SZZONES, KEY_READ | KEY_WRITE) == ERROR_SUCCESS)
  736. {
  737. if (regKey.QueryValue(&dwSelfHealCount, pszSelfHealCount) != ERROR_SUCCESS)
  738. dwSelfHealCount = 0;
  739. dwSelfHealCount++;
  740. regKey.SetValue(dwSelfHealCount, pszSelfHealCount);
  741. }
  742. bRet = TRUE;
  743. }
  744. else
  745. bRet = FALSE;
  746. return bRet;
  747. }
  748. CRegZone * CRegZoneContainer::GetRegZoneByName(LPCTSTR lpName) const
  749. {
  750. DWORD dwIndex = 0;
  751. CRegZone *pRegZone = NULL;
  752. for ( ; dwIndex < m_cZones; dwIndex++ )
  753. {
  754. pRegZone = m_ppRegZones[dwIndex] ;
  755. if (pRegZone && StrCmpIW(pRegZone->GetZoneName(), lpName) == 0)
  756. break;
  757. }
  758. return pRegZone;
  759. }
  760. CRegZone * CRegZoneContainer::GetRegZoneById(DWORD dwZoneId) const
  761. {
  762. DWORD dwIndex = 0;
  763. CRegZone * pReturnZone = NULL;
  764. for (; dwIndex < m_cZones ; dwIndex++ )
  765. {
  766. CRegZone * pRegZone = m_ppRegZones[dwIndex];
  767. if (pRegZone == NULL)
  768. {
  769. // This shouldn't happen but a safety check doesn't hurt.
  770. break;
  771. }
  772. else if (pRegZone->GetZoneId() == dwZoneId)
  773. {
  774. pReturnZone = pRegZone;
  775. break; // Got it
  776. }
  777. else if (pRegZone->GetZoneId() > dwZoneId)
  778. {
  779. break;
  780. }
  781. }
  782. return pReturnZone;
  783. }
  784. // Zone Enumeration functions.
  785. BOOL CRegZoneContainer::VerifyZoneEnum(DWORD dwEnum ) const
  786. {
  787. BOOL bFound = FALSE;
  788. CZoneEnumList *pNext = m_pZoneEnumList;
  789. while (pNext)
  790. {
  791. if (pNext->dwEnum == dwEnum)
  792. {
  793. bFound = TRUE;
  794. break;
  795. }
  796. pNext = pNext->next;
  797. }
  798. return bFound;
  799. }
  800. STDMETHODIMP CRegZoneContainer::CreateZoneEnumerator(DWORD* pdwEnum, DWORD *pdwCount)
  801. {
  802. if (pdwEnum == NULL || pdwCount == NULL)
  803. return E_INVALIDARG;
  804. if (m_cZones == 0)
  805. {
  806. return E_FAIL;
  807. }
  808. CZoneEnumList *pEnumListElem = new CZoneEnumList;
  809. if (pEnumListElem == NULL)
  810. return E_OUTOFMEMORY;
  811. pEnumListElem->dwEnum = m_dwNextEnum++;
  812. EnterCriticalSection(&m_csect);
  813. if (m_pZoneEnumList == NULL)
  814. {
  815. pEnumListElem->next = NULL;
  816. m_pZoneEnumList = pEnumListElem;
  817. }
  818. else
  819. {
  820. pEnumListElem->next = m_pZoneEnumList;
  821. m_pZoneEnumList = pEnumListElem;
  822. }
  823. *pdwEnum = m_pZoneEnumList->dwEnum;
  824. *pdwCount = m_cZones;
  825. TransAssert(VerifyZoneEnum(*pdwEnum));
  826. LeaveCriticalSection(&m_csect);
  827. return S_OK;
  828. }
  829. STDMETHODIMP CRegZoneContainer::GetZoneAt(DWORD dwEnum, DWORD dwIndex, DWORD *pdwZone)
  830. {
  831. if (!VerifyZoneEnum(dwEnum) || dwIndex >= m_cZones)
  832. {
  833. return E_INVALIDARG;
  834. }
  835. if (m_ppRegZones && m_ppRegZones[dwIndex])
  836. {
  837. *pdwZone = m_ppRegZones[dwIndex]->GetZoneId();
  838. return S_OK;
  839. }
  840. else
  841. {
  842. return E_OUTOFMEMORY;
  843. }
  844. }
  845. STDMETHODIMP CRegZoneContainer::DestroyZoneEnumerator(DWORD dwEnum)
  846. {
  847. HRESULT hr = S_OK;
  848. CZoneEnumList *pDelete = NULL;
  849. EnterCriticalSection(&m_csect);
  850. if (m_pZoneEnumList == NULL)
  851. {
  852. }
  853. else if (m_pZoneEnumList->dwEnum == dwEnum)
  854. {
  855. pDelete = m_pZoneEnumList;
  856. m_pZoneEnumList = pDelete->next;
  857. }
  858. else {
  859. CZoneEnumList *pCurr = m_pZoneEnumList;
  860. while (pCurr != NULL)
  861. {
  862. if (pCurr->next && pCurr->next->dwEnum == dwEnum)
  863. {
  864. pDelete = pCurr->next;
  865. pCurr->next = pDelete->next;
  866. break;
  867. }
  868. pCurr = pCurr->next;
  869. }
  870. }
  871. if (pDelete == NULL)
  872. {
  873. // Didn't find the entry must be an invalid Enumerator.
  874. hr = E_INVALIDARG;
  875. }
  876. else
  877. {
  878. delete pDelete;
  879. hr = S_OK;
  880. }
  881. LeaveCriticalSection(&m_csect);
  882. return hr;
  883. }
  884. //=============================================================================
  885. // CRegZoneCache methods
  886. //=============================================================================
  887. CRegZone::CRegZoneCache::CRegZoneCache(void)
  888. {
  889. InitializeCriticalSection(&m_csectZoneCache);
  890. // single static object, so this only gets inited once per
  891. // process.
  892. s_hMutexCounter = CreateMutexA(NULL, FALSE, "ZonesCacheCounterMutex");
  893. m_iAdd = 0;
  894. }
  895. CRegZone::CRegZoneCache::~CRegZoneCache(void)
  896. {
  897. Flush();
  898. DeleteCriticalSection(&m_csectZoneCache) ;
  899. CloseHandle(s_hMutexCounter);
  900. }
  901. BOOL
  902. CRegZone::CRegZoneCache::Lookup(DWORD dwZone, LPTSTR lpZonePath, DWORD dwAction, BOOL fUseHKLM, DWORD *pdwPolicy)
  903. {
  904. BOOL fFound = FALSE;
  905. int iEntry = URLZONE_FINDCACHEENTRY;
  906. TransAssert(iEntry < MAX_REG_ZONE_CACHE);
  907. EnterCriticalSection(&m_csectZoneCache);
  908. if ( !IsCounterEqual() )
  909. Flush();
  910. fFound = FindCacheEntry(dwZone, dwAction, fUseHKLM, iEntry );
  911. if (fFound)
  912. {
  913. if (pdwPolicy)
  914. {
  915. *pdwPolicy = m_arzce[iEntry].m_dwPolicy;
  916. }
  917. }
  918. else
  919. {
  920. // Convert the Action to a string.
  921. #ifndef unix
  922. TCHAR wsz[9]; // FFFFFFFF\0
  923. #else
  924. TCHAR wsz[(sizeof(DWORD)+1)*sizeof(WCHAR)];
  925. #endif /* unix */
  926. if (DwToWchar(dwAction, wsz, 16))
  927. {
  928. CRegKey regKey(fUseHKLM);
  929. if (regKey.Open(NULL, lpZonePath, KEY_READ) == ERROR_SUCCESS)
  930. {
  931. if (regKey.QueryValue(pdwPolicy, wsz) == ERROR_SUCCESS)
  932. {
  933. fFound = TRUE;
  934. Add(dwZone, dwAction, fUseHKLM, *pdwPolicy, iEntry);
  935. }
  936. }
  937. else
  938. {
  939. // BUGBUG:: We have to be able to deal with this situation and not just bail.
  940. // Possibilities: Setup defaults here if we can create and write to the key
  941. TransAssert(FALSE);
  942. }
  943. }
  944. else
  945. {
  946. TransAssert(FALSE);
  947. }
  948. }
  949. LeaveCriticalSection(&m_csectZoneCache);
  950. return fFound;
  951. }
  952. void
  953. CRegZone::CRegZoneCache::Add(DWORD dwZone, DWORD dwAction, BOOL fUseHKLM, DWORD dwPolicy, int iEntry)
  954. {
  955. BOOL fFound;
  956. TransAssert(iEntry < MAX_REG_ZONE_CACHE);
  957. EnterCriticalSection(&m_csectZoneCache);
  958. if ( !IsCounterEqual() )
  959. Flush();
  960. if(iEntry == URLZONE_FINDCACHEENTRY) // using optional param that indicates the entry we want to add so don't bother doing a find.
  961. fFound = FindCacheEntry(dwZone, dwAction, fUseHKLM, iEntry ); // found or not, iEntry will be the right place to set it.
  962. m_arzce[iEntry].Set(dwZone, dwAction, fUseHKLM, dwPolicy);
  963. SetToCurrentCounter(); // validate this cache.
  964. LeaveCriticalSection(&m_csectZoneCache);
  965. }
  966. void
  967. CRegZone::CRegZoneCache::Flush(void)
  968. {
  969. int i;
  970. EnterCriticalSection(&m_csectZoneCache);
  971. for ( i = 0; i < MAX_REG_ZONE_CACHE; i++ )
  972. m_arzce[i].Flush();
  973. m_iAdd = 0;
  974. LeaveCriticalSection(&m_csectZoneCache);
  975. }
  976. // Is the counter we saved with the cache entry, equal to the current counter.
  977. BOOL
  978. CRegZone::CRegZoneCache::IsCounterEqual( ) const
  979. {
  980. CExclusiveLock lock(s_hMutexCounter);
  981. LPDWORD lpdwCounter = (LPDWORD)g_SharedMem.GetPtr(SM_REGZONECHANGE_COUNTER);
  982. // If we couldn't create the shared memory for some reason, we just assume our cache is up to date.
  983. if (lpdwCounter == NULL)
  984. return TRUE;
  985. return (m_dwPrevCounter == *lpdwCounter);
  986. }
  987. VOID
  988. CRegZone::CRegZoneCache::SetToCurrentCounter( )
  989. {
  990. CExclusiveLock lock(s_hMutexCounter);
  991. LPDWORD lpdwCounter = (LPDWORD)g_SharedMem.GetPtr(SM_REGZONECHANGE_COUNTER);
  992. if (lpdwCounter == NULL)
  993. return;
  994. m_dwPrevCounter = *lpdwCounter;
  995. }
  996. VOID
  997. CRegZone::CRegZoneCache::IncrementGlobalCounter( )
  998. {
  999. CExclusiveLock lock(s_hMutexCounter);
  1000. LPDWORD lpdwCounter = (LPDWORD)g_SharedMem.GetPtr(SM_REGZONECHANGE_COUNTER);
  1001. if (lpdwCounter == NULL)
  1002. return;
  1003. (*lpdwCounter)++;
  1004. }
  1005. BOOL
  1006. CRegZone::CRegZoneCache::FindCacheEntry(DWORD dwZone, DWORD dwAction, BOOL fUseHKLM, int& riEntry )
  1007. {
  1008. BOOL fFound = FALSE;
  1009. for ( riEntry = 0; (m_arzce[riEntry].m_dwZone != ZONEID_INVALID) && (riEntry < MAX_REG_ZONE_CACHE); riEntry++ )
  1010. {
  1011. if ( m_arzce[riEntry].m_dwZone == dwZone &&
  1012. m_arzce[riEntry].m_dwAction == dwAction &&
  1013. m_arzce[riEntry].m_fUseHKLM == fUseHKLM )
  1014. {
  1015. fFound = TRUE;
  1016. break;
  1017. }
  1018. }
  1019. if(!fFound)
  1020. {
  1021. riEntry = m_iAdd;
  1022. m_iAdd = (m_iAdd + 1) % MAX_REG_ZONE_CACHE; // next index to add an entry that's not found
  1023. }
  1024. return fFound;
  1025. }
  1026. void
  1027. CRegZone::CRegZoneCache::CRegZoneCacheEntry::Set(DWORD dwZone, DWORD dwAction, BOOL fUseHKLM, DWORD dwPolicy)
  1028. {
  1029. m_dwZone = dwZone;
  1030. m_dwAction = dwAction;
  1031. m_fUseHKLM = fUseHKLM;
  1032. m_dwPolicy = dwPolicy;
  1033. }
  1034. void
  1035. CRegZone::CRegZoneCache::CRegZoneCacheEntry::Flush(void)
  1036. {
  1037. m_dwZone = ZONEID_INVALID;
  1038. }