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.

399 lines
12 KiB

  1. //---------------------------------------------------------------------------
  2. // ThemeFile.cpp - manages loaded theme files
  3. //---------------------------------------------------------------------------
  4. #include "stdafx.h"
  5. #include "ThemeFile.h"
  6. #include "Loader.h"
  7. #include "Services.h"
  8. //---------------------------------------------------------------------------
  9. CUxThemeFile::CUxThemeFile()
  10. {
  11. StringCchCopyA(_szHead, ARRAYSIZE(_szHead), "thmfile");
  12. StringCchCopyA(_szTail, ARRAYSIZE(_szTail), "end");
  13. Reset();
  14. }
  15. //---------------------------------------------------------------------------
  16. CUxThemeFile::~CUxThemeFile()
  17. {
  18. if (_pbThemeData || _hMemoryMap)
  19. CloseFile();
  20. StringCchCopyA(_szHead, ARRAYSIZE(_szHead), "deleted");
  21. }
  22. //---------------------------------------------------------------------------
  23. __inline bool CUxThemeFile::IsReady()
  24. {
  25. THEMEHDR *hdr = (THEMEHDR *)_pbThemeData;
  26. if (hdr != NULL && ((hdr->dwFlags & SECTION_READY) != 0))
  27. {
  28. return true;
  29. }
  30. return false;
  31. }
  32. //---------------------------------------------------------------------------
  33. __inline bool CUxThemeFile::IsGlobal()
  34. {
  35. THEMEHDR *hdr = (THEMEHDR *)_pbThemeData;
  36. if (hdr != NULL && ((hdr->dwFlags & SECTION_GLOBAL) != 0))
  37. {
  38. return true;
  39. }
  40. return false;
  41. }
  42. //---------------------------------------------------------------------------
  43. __inline bool CUxThemeFile::HasStockObjects()
  44. {
  45. THEMEHDR *hdr = (THEMEHDR *)_pbThemeData;
  46. if (hdr != NULL && ((hdr->dwFlags & SECTION_HASSTOCKOBJECTS) != 0))
  47. {
  48. return true;
  49. }
  50. return false;
  51. }
  52. //---------------------------------------------------------------------------
  53. #ifdef DEBUG
  54. void _CreateDebugSectionName( LPCWSTR pszBasicName, OUT LPWSTR pszName, IN ULONG cchName )
  55. {
  56. static DWORD dwRand = GetTickCount(); // rand seed
  57. dwRand = (dwRand * 214013L + 2531011L); // randomize
  58. DWORD dwUnique = (GetTickCount() | dwRand | (GetCurrentThreadId() << 8) | (GetCurrentProcessId() << 16));
  59. StringCchPrintfW(pszName, cchName,
  60. L"%s_%d_%d_%08lX",
  61. pszBasicName,
  62. NtCurrentPeb()->SessionId, // winlogon can't load/unload themes in different sessions.
  63. GetProcessWindowStation(), // winlogon can't load/unload themes in different winstas
  64. dwUnique);
  65. }
  66. #endif DEBUG
  67. //---------------------------------------------------------------------------
  68. HRESULT CUxThemeFile::CreateFile(int iLength, BOOL fReserve)
  69. {
  70. Log(LOG_TM, L"CUxThemeFile::CreateFile");
  71. HRESULT hr = S_OK;
  72. if (_pbThemeData)
  73. CloseFile();
  74. //---- we rely on all theme section names containing "ThemeSection" in CHK build so ----
  75. //---- devs/testers can verify that all handles to old theme sections are released. ----
  76. //---- For FRE builds, we want a NULL name to prevent name squatting attacks. ----
  77. WCHAR *pszName = NULL;
  78. #ifdef DEBUG
  79. WCHAR szSectionName[MAX_PATH];
  80. _CreateDebugSectionName(L"Debug_Create_ThemeSection", szSectionName, ARRAYSIZE(szSectionName));
  81. pszName = szSectionName;
  82. #endif
  83. _hMemoryMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
  84. PAGE_READWRITE | (fReserve ? SEC_RESERVE : 0), 0, iLength, pszName);
  85. if (! _hMemoryMap)
  86. {
  87. Log(LOG_ALWAYS, L"CUxThemeFile::CreateFile: could not create shared memory mapping");
  88. hr = MakeErrorLast();
  89. goto exit;
  90. }
  91. _pbThemeData = (BYTE *)MapViewOfFile(_hMemoryMap, FILE_MAP_WRITE, 0, 0, 0);
  92. if (! _pbThemeData)
  93. {
  94. Log(LOG_ALWAYS, L"CUxThemeFile::CreateFile: could not create shared memory view");
  95. CloseHandle(_hMemoryMap);
  96. hr = MakeErrorLast();
  97. goto exit;
  98. }
  99. Log(LOG_TMHANDLE, L"CUxThemeFile::CreateFile FILE CREATED: len=%d, addr=0x%x",
  100. iLength, _pbThemeData);
  101. exit:
  102. if (FAILED(hr))
  103. Reset();
  104. return hr;
  105. }
  106. //---------------------------------------------------------------------------
  107. HRESULT CUxThemeFile::CreateFromSection(HANDLE hSection)
  108. {
  109. Log(LOG_TM, L"CUxThemeFile::CreateFromSection");
  110. HRESULT hr = S_OK;
  111. void *pvOld = NULL;
  112. //---- ensure we start with all previous handles closed ----
  113. if (_pbThemeData)
  114. CloseFile();
  115. //---- get access to source section data ----
  116. pvOld = MapViewOfFile(hSection, FILE_MAP_READ, 0, 0, 0);
  117. if (! pvOld)
  118. {
  119. hr = MakeErrorLast();
  120. goto exit;
  121. }
  122. THEMEHDR *pHdr = (THEMEHDR *)pvOld;
  123. DWORD dwTrueSize = pHdr->dwTotalLength;
  124. //---- we rely on all theme section names containing "ThemeSection" in CHK build so ----
  125. //---- devs/testers can verify that all handles to old theme sections are released. ----
  126. //---- For FRE builds, we want a NULL name to prevent name squatting attacks. ----
  127. WCHAR *pszName = NULL;
  128. #ifdef DEBUG
  129. WCHAR szSectionName[MAX_PATH];
  130. _CreateDebugSectionName(L"Debug_CreateFromSection_ThemeSection", szSectionName, ARRAYSIZE(szSectionName));
  131. pszName = szSectionName;
  132. #endif
  133. //---- create the new section ----
  134. _hMemoryMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
  135. PAGE_READWRITE, 0, dwTrueSize, pszName);
  136. DWORD dwErr = GetLastError();
  137. if( ERROR_ALREADY_EXISTS == dwErr )
  138. {
  139. Log(LOG_ALWAYS, L"CUxThemeFile::CreateFromSection: shared theme section mapping already exists");
  140. ASSERT(FALSE);
  141. }
  142. if (! _hMemoryMap)
  143. {
  144. hr = HRESULT_FROM_WIN32(dwErr);
  145. Log(LOG_ALWAYS, L"CUxThemeFile::CreateFromSection: could not create shared memory mapping (%ld)", dwErr);
  146. goto exit;
  147. }
  148. //---- get access to new section data ----
  149. _pbThemeData = (BYTE *)MapViewOfFile(_hMemoryMap, FILE_MAP_WRITE, 0, 0, 0);
  150. if (! _pbThemeData)
  151. {
  152. hr = MakeErrorLast();
  153. Log(LOG_ALWAYS, L"CThemeFile::CreateFromSection: could not create shared memory view");
  154. goto exit;
  155. }
  156. //---- copy the data from the old section to the new section ----
  157. __try
  158. {
  159. CopyMemory(_pbThemeData, pvOld, dwTrueSize);
  160. }
  161. __except (EXCEPTION_EXECUTE_HANDLER)
  162. {
  163. hr = GetExceptionCode();
  164. goto exit;
  165. }
  166. //---- ensure version, checksum, etc. is all looking good ----
  167. hr = ValidateThemeData(TRUE);
  168. if (FAILED(hr))
  169. goto exit;
  170. Log(LOG_TMHANDLE, L"CUxThemeFile::CreateFromSection FILE CREATED: addr=0x%x",
  171. _pbThemeData);
  172. exit:
  173. if (pvOld != NULL)
  174. UnmapViewOfFile(pvOld);
  175. if (FAILED(hr))
  176. CloseFile();
  177. return hr;
  178. }
  179. //---------------------------------------------------------------------------
  180. // If fCleanupOnFailure is FALSE, we won't close the handle passed, even on failure.
  181. //---------------------------------------------------------------------------
  182. HRESULT CUxThemeFile::OpenFromHandle(
  183. HANDLE handle,
  184. DWORD dwDesiredAccess,
  185. BOOL fCleanupOnFailure)
  186. {
  187. HRESULT hr = S_OK;
  188. if (_pbThemeData)
  189. CloseFile();
  190. _pbThemeData = (BYTE *)MapViewOfFile(handle, dwDesiredAccess, 0, 0, 0);
  191. if (! _pbThemeData)
  192. {
  193. hr = MakeErrorLast();
  194. goto exit;
  195. }
  196. _hMemoryMap = handle;
  197. //---- ensure data is valid ----
  198. hr = ValidateThemeData(FALSE);
  199. if (FAILED(hr))
  200. {
  201. if (!fCleanupOnFailure)
  202. {
  203. _hMemoryMap = NULL; // don't give up the refcount on the handle
  204. CloseFile();
  205. }
  206. hr = MakeError32(ERROR_BAD_FORMAT);
  207. goto exit;
  208. }
  209. #ifdef DEBUG
  210. THEMEHDR *ph;
  211. ph = (THEMEHDR *)_pbThemeData;
  212. Log(LOG_TMHANDLE, L"CUxThemeFile::OpenFromHandle OPENED: num=%d, addr=0x%x",
  213. ph->iLoadId, _pbThemeData);
  214. #endif
  215. exit:
  216. if (FAILED(hr))
  217. {
  218. if (!fCleanupOnFailure)
  219. {
  220. Reset();
  221. }
  222. else
  223. {
  224. CloseFile();
  225. }
  226. }
  227. return hr;
  228. }
  229. //---------------------------------------------------------------------------
  230. HRESULT CUxThemeFile::ValidateThemeData(BOOL fFullCheck)
  231. {
  232. HRESULT hr = S_OK;
  233. THEMEHDR *hdr;
  234. if (! ValidateObj())
  235. {
  236. hr = MakeError32(ERROR_INTERNAL_ERROR);
  237. goto exit;
  238. }
  239. if (IsBadReadPtr(_pbThemeData, 4)) // sufficient test
  240. {
  241. hr = MakeError32(ERROR_BAD_FORMAT);
  242. goto exit;
  243. }
  244. hdr = (THEMEHDR *)_pbThemeData;
  245. if (0 != memcmp(hdr->szSignature, kszBeginCacheFileSignature, kcbBeginSignature)) // bad ptr
  246. {
  247. #ifdef DEBUG
  248. CHAR szSignature[kcbBeginSignature + 1];
  249. CopyMemory(szSignature, hdr->szSignature, kcbBeginSignature); // hdr->szSignature is not NULL-terminated
  250. szSignature[kcbBeginSignature] = '\0';
  251. Log(LOG_ERROR, L"ValidateThemeData(): bad header signature: %S", szSignature);
  252. #else
  253. Log(LOG_ERROR, L"ValidateThemeData(): bad header signature");
  254. #endif
  255. hr = MakeError32(ERROR_BAD_FORMAT);
  256. goto exit;
  257. }
  258. if (hdr->dwVersion != THEMEDATA_VERSION)
  259. {
  260. Log(LOG_ALWAYS, L"ValidateThemeData(): wrong theme data version: 0x%x", hdr->dwVersion);
  261. hr = MakeError32(ERROR_BAD_FORMAT);
  262. goto exit;
  263. }
  264. if (!IsReady()) // data not ready to use
  265. {
  266. Log(LOG_ALWAYS, L"ValidateThemeData(): data not READY - hdr->dwFlags=%x", hdr->dwFlags);
  267. hr = MakeError32(ERROR_BAD_FORMAT);
  268. goto exit;
  269. }
  270. if (!fFullCheck) // we are done
  271. goto exit;
  272. // Whistler:190200:Instead of checking the checksum, check the end of file signature, to avoid paging in everything
  273. if (0 != memcmp(_pbThemeData + hdr->dwTotalLength - kcbEndSignature, kszEndCacheFileSignature, kcbEndSignature))
  274. {
  275. Log(LOG_ERROR, L"ValidateThemeData(): bad end of file signature");
  276. hr = MakeError32(ERROR_BAD_FORMAT);
  277. goto exit;
  278. }
  279. exit:
  280. return hr;
  281. }
  282. //---------------------------------------------------------------------------
  283. void CUxThemeFile::CloseFile()
  284. {
  285. #ifdef DEBUG
  286. THEMEHDR *ph = (THEMEHDR *)_pbThemeData;
  287. if (ph != NULL)
  288. {
  289. Log(LOG_TMHANDLE, L"Share CLOSED: num=%d, addr=0x%x",
  290. ph->iLoadId, _pbThemeData);
  291. }
  292. #endif
  293. if (_hMemoryMap && HasStockObjects() && !IsGlobal())
  294. {
  295. CThemeServices::ClearStockObjects(_hMemoryMap);
  296. }
  297. if (_pbThemeData)
  298. UnmapViewOfFile(_pbThemeData);
  299. if (_hMemoryMap)
  300. CloseHandle(_hMemoryMap);
  301. Reset();
  302. }
  303. //---------------------------------------------------------------------------
  304. void CUxThemeFile::Reset()
  305. {
  306. _pbThemeData = NULL;
  307. _hMemoryMap = NULL;
  308. }
  309. //---------------------------------------------------------------------------
  310. BOOL CUxThemeFile::ValidateObj()
  311. {
  312. BOOL fValid = TRUE;
  313. //---- check object quickly ----
  314. if ( (! this)
  315. || (ULONGAT(_szHead) != 'fmht') // "thmf"
  316. || (ULONGAT(&_szHead[4]) != 'eli') // "ile"
  317. || (ULONGAT(_szTail) != 'dne')) // "end"
  318. {
  319. Log(LOG_ERROR, L"*** ERROR: Invalid CUxThemeFile Encountered, addr=0x%08x ****", this);
  320. fValid = FALSE;
  321. }
  322. return fValid;
  323. }
  324. //---------------------------------------------------------------------------
  325. HANDLE CUxThemeFile::Unload()
  326. {
  327. HANDLE handle = _hMemoryMap;
  328. if (_pbThemeData != NULL)
  329. {
  330. UnmapViewOfFile(_pbThemeData);
  331. }
  332. Reset(); // don't free handle
  333. return handle;
  334. }