Source code of Windows XP (NT5)
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.

373 lines
11 KiB

  1. #include "stdinc.h"
  2. #include "windows.h"
  3. #include "sxsapi.h"
  4. #include "sxsprotect.h"
  5. #include "sxssfcscan.h"
  6. #include "wintrust.h"
  7. #include "softpub.h"
  8. #include "strongname.h"
  9. #include "recover.h"
  10. static GUID WintrustVerifyProviderV2 = WINTRUST_ACTION_GENERIC_VERIFY_V2;
  11. BOOL
  12. SxspValidateEntireAssembly(
  13. DWORD dwFlags,
  14. const CAssemblyRecoveryInfo &RecoverInfo,
  15. DWORD &dwResult
  16. )
  17. {
  18. BOOL bSuccess = FALSE;
  19. const CSecurityMetaData &rSecurityData = RecoverInfo.GetSecurityInformation();
  20. FN_TRACE_WIN32(bSuccess);
  21. #define CHECKSHOULDSTOPFAIL { if (dwFlags & SXS_VALIDATE_ASM_FLAG_MODE_STOP_ON_FAIL) { bSuccess = TRUE; goto Exit; } }
  22. #define ADDFLAG(result, test, flag) { if (test) { (result) |= (flag); } else CHECKSHOULDSTOPFAIL }
  23. ManifestValidationResult ManifestValidity;
  24. CSecurityMetaData SecurityMetaData;
  25. CStringBuffer sbManifestPath;
  26. dwResult = 0;
  27. if (dwFlags == 0)
  28. {
  29. dwFlags = SXS_VALIDATE_ASM_FLAG_CHECK_EVERYTHING;
  30. dwFlags |= (SXS_VALIDATE_ASM_FLAG_MODE_STOP_ON_FAIL);
  31. }
  32. IFINVALID_FLAGS_EXIT_WIN32(dwFlags,
  33. SXS_VALIDATE_ASM_FLAG_CHECK_CATALOG |
  34. SXS_VALIDATE_ASM_FLAG_CHECK_FILES |
  35. SXS_VALIDATE_ASM_FLAG_CHECK_STRONGNAME |
  36. SXS_VALIDATE_ASM_FLAG_CHECK_CAT_STRONGNAME |
  37. SXS_VALIDATE_ASM_FLAG_MODE_STOP_ON_FAIL);
  38. //
  39. // Asking us to check the catalog when there's no catalog on the assembly
  40. // is a Bad Thing. Perhaps this should just return TRUE with a missing catalog?
  41. //
  42. PARAMETER_CHECK(dwFlags & SXS_VALIDATE_ASM_FLAG_CHECK_CATALOG);
  43. PARAMETER_CHECK(RecoverInfo.GetHasCatalog());
  44. #if DBG
  45. ::FusionpDbgPrintEx(
  46. FUSION_DBG_LEVEL_WFP,
  47. "SXS.DLL: %s() - Beginning protection scan of %ls, flags 0x%08x\n",
  48. __FUNCTION__,
  49. static_cast<PCWSTR>(RecoverInfo.GetAssemblyDirectoryName()),
  50. dwFlags);
  51. #endif
  52. IFW32FALSE_EXIT(::SxspResolveAssemblyManifestPath(RecoverInfo.GetAssemblyDirectoryName(), sbManifestPath));
  53. //
  54. // If we're checking the catalog, then do it. If the catalog is bad or
  55. // otherwise doesn't match the actual assembly, then we need to mark
  56. // ourselves as successful, then exit.
  57. //
  58. if (dwFlags & SXS_VALIDATE_ASM_FLAG_CHECK_CATALOG)
  59. {
  60. IFW32FALSE_EXIT(::SxspValidateManifestAgainstCatalog(
  61. sbManifestPath,
  62. ManifestValidity,
  63. 0));
  64. #if DBG
  65. FusionpDbgPrintEx(
  66. FUSION_DBG_LEVEL_WFP,
  67. "SXS.DLL: Manifest Validity = %ls\n",
  68. SxspManifestValidationResultToString(ManifestValidity));
  69. #endif
  70. ADDFLAG(
  71. dwResult,
  72. ManifestValidity == ManifestValidate_IsIntact,
  73. SXS_VALIDATE_ASM_FLAG_VALID_CATALOG);
  74. }
  75. //TODO: Problems - make sure that we validate the manifest against what's in the
  76. // registry. Maybe we need a special mode of incorporating assemblies (over a manifest)
  77. // that will just fill out the security data and nothing else...
  78. //
  79. // Validate the strong name of the assembly first.
  80. //
  81. if (dwFlags & SXS_VALIDATE_ASM_FLAG_CHECK_STRONGNAME)
  82. {
  83. //
  84. // JW 3/19/2001 - Public keys are NO LONGER IN THE BUILD, and as such
  85. // this check is moot.
  86. //
  87. ADDFLAG(dwResult, TRUE, SXS_VALIDATE_ASM_FLAG_VALID_STRONGNAME);
  88. }
  89. //
  90. // Let's open the catalog and scour through it certificate-wise
  91. // looking for a strong name that matches up.
  92. //
  93. if (dwFlags & SXS_VALIDATE_ASM_FLAG_CHECK_CAT_STRONGNAME)
  94. {
  95. CStringBuffer sbCatalogName;
  96. CSmallStringBuffer sbTheorheticalStrongName;
  97. const CFusionByteArray &rbaSignerPublicKey = rSecurityData.GetSignerPublicKeyTokenBits();
  98. CPublicKeyInformation PublicKeyInfo;
  99. BOOL bStrongNameFoundInCatalog;
  100. IFW32FALSE_EXIT(sbCatalogName.Win32Assign(sbManifestPath));
  101. IFW32FALSE_EXIT(sbCatalogName.Win32ChangePathExtension(
  102. FILE_EXTENSION_CATALOG,
  103. FILE_EXTENSION_CATALOG_CCH,
  104. eAddIfNoExtension));
  105. if (!PublicKeyInfo.Initialize(sbCatalogName))
  106. {
  107. const DWORD dwLastError = ::FusionpGetLastWin32Error();
  108. if ((dwLastError != ERROR_PATH_NOT_FOUND) &&
  109. (dwLastError != ERROR_FILE_NOT_FOUND))
  110. goto Exit;
  111. }
  112. IFW32FALSE_EXIT(
  113. ::SxspHashBytesToString(
  114. rbaSignerPublicKey.GetArrayPtr(),
  115. rbaSignerPublicKey.GetSize(),
  116. sbTheorheticalStrongName));
  117. IFW32FALSE_EXIT(
  118. PublicKeyInfo.DoesStrongNameMatchSigner(
  119. sbTheorheticalStrongName,
  120. bStrongNameFoundInCatalog));
  121. ADDFLAG(dwResult, bStrongNameFoundInCatalog, SXS_VALIDATE_ASM_FLAG_VALID_CAT_STRONGNAME);
  122. }
  123. //
  124. // Now, scan through all the files that are listed in the manifest and
  125. // ensure that they're all OK.
  126. //
  127. if (dwFlags & SXS_VALIDATE_ASM_FLAG_CHECK_FILES)
  128. {
  129. CStringBuffer sbTempScanPath;
  130. CStringBuffer sbAsmRootDir;
  131. const CBaseStringBuffer &sbAssemblyName = RecoverInfo.GetAssemblyDirectoryName();
  132. CFileInformationTableIter ContentTableIter(const_cast<CFileInformationTable&>(rSecurityData.GetFileDataTable()));
  133. HashValidateResult hvResult;
  134. BOOL bAllFilesMatch = TRUE;
  135. BOOL fTempBoolean;
  136. IFW32FALSE_EXIT(::SxspGetAssemblyRootDirectory(sbAsmRootDir));
  137. for (ContentTableIter.Reset();
  138. ContentTableIter.More();
  139. ContentTableIter.Next())
  140. {
  141. //
  142. // Cobble together a path to scan for the file in, based on the
  143. // assembly root directory, the 'name' of the assembly (note:
  144. // we can't use this to go backwards to get an identity,
  145. // unfortunately), and the name of the file to be validated.
  146. //
  147. PCWSTR wsString = ContentTableIter.GetKey();
  148. CMetaDataFileElement &HashEntry = ContentTableIter.GetValue();
  149. IFW32FALSE_EXIT(sbTempScanPath.Win32Format( L"%ls\\%ls\\%ls",
  150. static_cast<PCWSTR>(sbAsmRootDir),
  151. static_cast<PCWSTR>(sbAssemblyName),
  152. wsString));
  153. IFW32FALSE_EXIT_UNLESS( ::SxspValidateAllFileHashes(
  154. HashEntry,
  155. sbTempScanPath,
  156. hvResult ),
  157. FILE_OR_PATH_NOT_FOUND(::FusionpGetLastWin32Error()),
  158. fTempBoolean );
  159. if ( ( hvResult != HashValidate_Matches ) || ( fTempBoolean ) )
  160. {
  161. bAllFilesMatch = FALSE;
  162. }
  163. }
  164. ADDFLAG(dwResult, bAllFilesMatch, SXS_VALIDATE_ASM_FLAG_VALID_FILES);
  165. }
  166. //
  167. // Phew - should be done doing everything the user wanted us to.
  168. //
  169. bSuccess = TRUE;
  170. Exit:
  171. #if DBG
  172. FusionpDbgPrintEx(
  173. FUSION_DBG_LEVEL_WFP,
  174. "SXS.DLL: Done validating, result = 0x%08x, success = %d\n",
  175. dwResult,
  176. bSuccess);
  177. #endif
  178. return bSuccess;
  179. #undef CHECKSHOULDSTOPFAIL
  180. }
  181. //
  182. // Single-shot scanning
  183. //
  184. BOOL
  185. SxsProtectionPerformScanNowNoSEH(
  186. HWND hwProgressWindow,
  187. BOOL bValidate,
  188. BOOL bUIAllowed
  189. )
  190. {
  191. BOOL bSuccess = TRUE;
  192. FN_TRACE_WIN32(bSuccess);
  193. CFusionRegKey hkInstallRoot;
  194. WCHAR wcKeyNameBuffer[MAX_PATH];
  195. DWORD cchKeyName;
  196. ULONG ulRegOp;
  197. DWORD dwKeyIndex;
  198. CStringBuffer sbTemp;
  199. CStringBuffer sbAssemblyDirectory, sbManifestPath;
  200. //
  201. // If we're scanning, then we don't want to bother sxs-sfc with changes,
  202. // now do we?
  203. //
  204. // REVIEW: Handy way to get around sfc-sxs... start a series of scans, and
  205. // insert 'bad' files into assemblies while we're scanning.
  206. //
  207. SxsProtectionEnableProcessing(FALSE);
  208. bSuccess = TRUE;
  209. IFW32FALSE_EXIT(::SxspOpenAssemblyInstallationKey( 0, KEY_READ, hkInstallRoot ));
  210. dwKeyIndex = 0;
  211. while (true)
  212. {
  213. ulRegOp = ::RegEnumKeyExW(
  214. hkInstallRoot,
  215. dwKeyIndex++,
  216. wcKeyNameBuffer,
  217. &(cchKeyName = NUMBER_OF(wcKeyNameBuffer)),
  218. NULL,
  219. NULL,
  220. NULL,
  221. NULL);
  222. ::FusionpSetLastWin32Error(ulRegOp);
  223. if (ulRegOp == ERROR_NO_MORE_ITEMS)
  224. break;
  225. else if (ulRegOp != ERROR_SUCCESS)
  226. ORIGINATE_WIN32_FAILURE_AND_EXIT(RegEnumKeyExW, ulRegOp);
  227. else
  228. {
  229. CAssemblyRecoveryInfo ri;
  230. bool fHasAssociatedAssembly;
  231. IFW32FALSE_EXIT(sbTemp.Win32Assign(wcKeyNameBuffer, cchKeyName));
  232. IFW32FALSE_EXIT(ri.AssociateWithAssembly(sbTemp, fHasAssociatedAssembly));
  233. if (!fHasAssociatedAssembly)
  234. {
  235. ::FusionpDbgPrintEx(
  236. FUSION_DBG_LEVEL_WFP,
  237. "SXS.DLL: %s() - We found the assembly %ls in the registry, but were not able to associate it with an assembly\n",
  238. __FUNCTION__,
  239. static_cast<PCWSTR>(sbTemp));
  240. }
  241. else if (!ri.GetHasCatalog())
  242. {
  243. ::FusionpDbgPrintEx(
  244. FUSION_DBG_LEVEL_WFP,
  245. "SXS.DLL: %s() - Assembly %ls in registry, no catalog, not validating.\n",
  246. __FUNCTION__,
  247. static_cast<PCWSTR>(sbTemp));
  248. }
  249. else
  250. {
  251. DWORD dwValidateMode, dwResult;
  252. SxsRecoveryResult RecoverResult;
  253. dwValidateMode = SXS_VALIDATE_ASM_FLAG_CHECK_EVERYTHING;
  254. IFW32FALSE_EXIT(::SxspValidateEntireAssembly(
  255. dwValidateMode,
  256. ri,
  257. dwResult));
  258. if (dwResult != SXS_VALIDATE_ASM_FLAG_VALID_PERFECT)
  259. {
  260. #if DBG
  261. ::FusionpDbgPrintEx(
  262. FUSION_DBG_LEVEL_WFP | FUSION_DBG_LEVEL_ERROR,
  263. "SXS.DLL: %s() - Scan of %ls failed one or more, flagset 0x%08x\n",
  264. __FUNCTION__,
  265. static_cast<PCWSTR>(sbTemp),
  266. dwResult);
  267. #endif
  268. IFW32FALSE_EXIT(
  269. ::SxspRecoverAssembly(
  270. ri,
  271. NULL,
  272. RecoverResult));
  273. #if DBG
  274. if (RecoverResult != Recover_OK)
  275. {
  276. FusionpDbgPrintEx(
  277. FUSION_DBG_LEVEL_WFP | FUSION_DBG_LEVEL_ERROR,
  278. "SXS.DLL: %s() - Reinstallation of assembly %ls failed, status %ls\n",
  279. static_cast<PCWSTR>(sbTemp),
  280. SxspRecoveryResultToString(RecoverResult));
  281. }
  282. #endif
  283. }
  284. }
  285. }
  286. }
  287. bSuccess = TRUE;
  288. Exit:
  289. return bSuccess;
  290. }
  291. BOOL
  292. SxsProtectionPerformScanNow(
  293. HWND hwProgressWindow,
  294. BOOL bValidate,
  295. BOOL bUIAllowed
  296. )
  297. {
  298. BOOL bSuccess = TRUE;
  299. __try
  300. {
  301. bSuccess = ::SxsProtectionPerformScanNowNoSEH(hwProgressWindow, bValidate, bUIAllowed);
  302. }
  303. __except(SXSP_EXCEPTION_FILTER())
  304. {
  305. ::FusionpDbgPrintEx(
  306. FUSION_DBG_LEVEL_WFP | FUSION_DBG_LEVEL_ERROR,
  307. "SXS.DLL: " __FUNCTION__ "(): Aborting scan, returning false - Exception!");
  308. }
  309. //
  310. // Always reenable sfc notifications!
  311. //
  312. ::SxsProtectionEnableProcessing(TRUE);
  313. return bSuccess;
  314. }