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.

373 lines
12 KiB

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