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.

2274 lines
95 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation
  3. Module Name:
  4. dllredir.cpp
  5. Abstract:
  6. Activation context section contributor for the DLL Redirection section.
  7. Author:
  8. Michael J. Grier (MGrier) 23-Feb-2000
  9. Revision History:
  10. Jay Krell (a-JayK, JayKrell) April 2000 install support
  11. --*/
  12. #include "stdinc.h"
  13. #include <windows.h>
  14. #include "sxsp.h"
  15. #include "fusioneventlog.h"
  16. #include "sxsinstall.h"
  17. #include "dllredir.h"
  18. #include "cteestream.h"
  19. #include "sxspath.h"
  20. #include "hashfile.h"
  21. #if FUSION_PRECOMPILED_MANIFEST
  22. #define PRECOMPILED_MANIFEST_EXTENSION L".precompiled"
  23. #include "pcmwriterstream.h"
  24. #endif
  25. #include "sxsexceptionhandling.h"
  26. #include "strongname.h"
  27. #include "csecuritymetadata.h"
  28. #include "cstreamtap.h"
  29. //
  30. // We need to hook this up to the setuplog file functionality.
  31. //
  32. #define SxspInstallPrint FusionpDbgPrint
  33. #define POST_WHISTLER_BETA1 0
  34. //
  35. // This is the default hash algorithm for manifests. If no algorithm
  36. // is specified with hashalg="foo", then it's SHA1.
  37. //
  38. #define FUSION_DEFAULT_HASH_ALGORITHM (CALG_SHA1)
  39. /*-----------------------------------------------------------------------------*/
  40. DECLARE_STD_ATTRIBUTE_NAME_DESCRIPTOR(name);
  41. DECLARE_STD_ATTRIBUTE_NAME_DESCRIPTOR(sourceName);
  42. DECLARE_STD_ATTRIBUTE_NAME_DESCRIPTOR(loadFrom);
  43. DECLARE_STD_ATTRIBUTE_NAME_DESCRIPTOR(hash);
  44. DECLARE_STD_ATTRIBUTE_NAME_DESCRIPTOR(hashalg);
  45. typedef struct _DLL_REDIRECTION_CONTEXT
  46. {
  47. _DLL_REDIRECTION_CONTEXT() { }
  48. } DLL_REDIRECTION_CONTEXT, *PDLL_REDIRECTION_CONTEXT;
  49. typedef struct _DLL_REDIRECTION_ENTRY
  50. {
  51. _DLL_REDIRECTION_ENTRY() :
  52. AssemblyPathIsLoadFrom(false),
  53. PathIncludesBaseName(false),
  54. SystemDefaultRedirectedSystem32Dll(false)
  55. { }
  56. CStringBuffer AssemblyPathBuffer;
  57. bool AssemblyPathIsLoadFrom; // Set to true when a <file name="x" loadfrom="%windir%\system32\"/> is found
  58. bool PathIncludesBaseName; // Set to true when a <file name="x" loadfrom="%windir%\x.dll"/> is found
  59. bool SystemDefaultRedirectedSystem32Dll;
  60. CStringBuffer FileNameBuffer;
  61. private:
  62. _DLL_REDIRECTION_ENTRY(const _DLL_REDIRECTION_ENTRY &);
  63. void operator =(const _DLL_REDIRECTION_ENTRY &);
  64. } DLL_REDIRECTION_ENTRY, *PDLL_REDIRECTION_ENTRY;
  65. /*-----------------------------------------------------------------------------*/
  66. VOID
  67. __fastcall
  68. SxspDllRedirectionContributorCallback(
  69. PACTCTXCTB_CALLBACK_DATA Data
  70. )
  71. {
  72. FN_TRACE();
  73. CDllRedir* pThis = NULL;
  74. switch (Data->Header.Reason)
  75. {
  76. case ACTCTXCTB_CBREASON_ACTCTXGENBEGINNING:
  77. Data->GenBeginning.Success = FALSE;
  78. if (Data->Header.ActCtxGenContext == NULL)
  79. {
  80. IFALLOCFAILED_EXIT(pThis = new CDllRedir);
  81. Data->Header.ActCtxGenContext = pThis;
  82. }
  83. // fall through
  84. default:
  85. pThis = reinterpret_cast<CDllRedir*>(Data->Header.ActCtxGenContext);
  86. pThis->ContributorCallback(Data);
  87. if (Data->Header.Reason == ACTCTXCTB_CBREASON_ACTCTXGENENDED)
  88. FUSION_DELETE_SINGLETON(pThis);
  89. break;
  90. }
  91. Exit:
  92. ;
  93. }
  94. /*-----------------------------------------------------------------------------
  95. This function is called on Win9x if we crash during an install, on the
  96. next login. It deletes temporary files/directories.
  97. -----------------------------------------------------------------------------*/
  98. VOID
  99. CALLBACK
  100. SxspRunDllDeleteDirectory(HWND hwnd, HINSTANCE hinst, PSTR lpszCmdLine, int nCmdShow)
  101. {
  102. FN_TRACE_SMART_TLS();
  103. CStringBuffer buffer;
  104. if (buffer.Win32Assign(lpszCmdLine, ::strlen(lpszCmdLine)))
  105. {
  106. SxspDeleteDirectory(buffer);
  107. }
  108. }
  109. /*-----------------------------------------------------------------------------
  110. This function is called on Nt if we crash during an install, on the
  111. next login. It deletes temporary files/directories.
  112. -----------------------------------------------------------------------------*/
  113. VOID
  114. CALLBACK
  115. SxspRunDllDeleteDirectoryW(HWND hwnd, HINSTANCE hinst, PWSTR lpszCmdLine, int nCmdShow)
  116. {
  117. FN_TRACE_SMART_TLS();
  118. CSmallStringBuffer buffer;
  119. if (buffer.Win32Assign(lpszCmdLine, ::wcslen(lpszCmdLine)))
  120. {
  121. SxspDeleteDirectory(buffer);
  122. }
  123. }
  124. /*-----------------------------------------------------------------------------
  125. This function sets up state for an upcoming series of installs, installs
  126. of assemblies/files.
  127. -----------------------------------------------------------------------------*/
  128. BOOL
  129. CDllRedir::BeginInstall(
  130. PACTCTXCTB_CALLBACK_DATA Data
  131. )
  132. {
  133. BOOL fSuccess = FALSE;
  134. FN_TRACE_WIN32(fSuccess);
  135. const DWORD dwManifestOperationFlags = Data->Header.ManifestOperationFlags;
  136. const bool fTransactional = (dwManifestOperationFlags & MANIFEST_OPERATION_INSTALL_FLAG_NOT_TRANSACTIONAL) == 0;
  137. CSmallStringBuffer ManifestDirectory;
  138. if (!fTransactional)
  139. {
  140. //
  141. // m_strTempRootSlash is now actually the real root
  142. //
  143. IFW32FALSE_EXIT(::SxspGetAssemblyRootDirectory(m_strTempRootSlash));
  144. IFW32FALSE_EXIT(m_strTempRootSlash.Win32RemoveTrailingPathSeparators()); // CreateDirectory doesn't like them
  145. // create \winnt\WinSxs, must not delete even on failure
  146. if (::CreateDirectoryW(m_strTempRootSlash, NULL))
  147. {
  148. // We don't care if this fails.
  149. ::SetFileAttributesW(m_strTempRootSlash, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
  150. }
  151. else if (::FusionpGetLastWin32Error() != ERROR_ALREADY_EXISTS)
  152. {
  153. goto Exit;
  154. }
  155. }
  156. else
  157. {
  158. CSmallStringBuffer uidBuffer;
  159. // Create the directory first, not the RunOnce value, in case the directory
  160. // already exists; we don't want to put it in the registry, then crash,
  161. // then end up deleting someone else's stuff.
  162. //
  163. // If we crash between creating the directory and setting the RunOnce value,
  164. // we do leak the directory. Darn. (You should be able to create/open
  165. // with delete on close/exit, then turn that off once you get far enough,
  166. // or in our case, never, and it should be applicable recursively..Win32
  167. // is not yet sufficient.)
  168. IFW32FALSE_EXIT(::SxspCreateWinSxsTempDirectory(m_strTempRootSlash, NULL, &uidBuffer, NULL));
  169. // ok, we created the directory, now make a note in the registry to delete it
  170. // upon login, if we crash
  171. IFALLOCFAILED_EXIT(m_pRunOnce = new CRunOnceDeleteDirectory);
  172. IFW32FALSE_EXIT(m_pRunOnce->Initialize(m_strTempRootSlash, &uidBuffer));
  173. }
  174. // create winnt\winsxs\manifests
  175. IFW32FALSE_EXIT(ManifestDirectory.Win32Assign(m_strTempRootSlash, m_strTempRootSlash.Cch()));
  176. IFW32FALSE_EXIT(ManifestDirectory.Win32AppendPathElement(MANIFEST_ROOT_DIRECTORY_NAME, NUMBER_OF(MANIFEST_ROOT_DIRECTORY_NAME) - 1));
  177. if (CreateDirectoryW(ManifestDirectory, NULL))
  178. {
  179. // We don't care if this fails.
  180. ::SetFileAttributesW(ManifestDirectory, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
  181. }
  182. else if (::FusionpGetLastWin32Error() != ERROR_ALREADY_EXISTS)
  183. {
  184. goto Exit;
  185. }
  186. IFW32FALSE_EXIT(m_strTempRootSlash.Win32Append(L"\\", 1));
  187. // fix it up..not sure this accomplishes anything..
  188. // if (!ActCtxGenCtx->m_AssemblyRootDirectoryBuffer.Win32Assign(m_strTempRootSlash))
  189. // {
  190. // goto Exit;
  191. // }
  192. fSuccess = TRUE;
  193. Exit:
  194. if (!fSuccess && fTransactional)
  195. {
  196. // rollback, which is not coincidentally identical to EndInstall aborting,
  197. // except that
  198. // here RemoveDirectoryW would be sufficient, there SxspDeleteDirectory is needed
  199. // here, we already know there is an error, and cleanup can't produce another
  200. // there, they have extra logic to progagage errors
  201. // we mask that by preserve LastError since we preserve it ourselves
  202. // and ignore the return value
  203. const DWORD dwLastError = ::FusionpGetLastWin32Error();
  204. const DWORD dwManifestOperationFlagsSaved = Data->Header.ManifestOperationFlags;
  205. Data->Header.ManifestOperationFlags |= MANIFEST_OPERATION_INSTALL_FLAG_ABORT;
  206. this->EndInstall(Data);
  207. Data->Header.ManifestOperationFlags = dwManifestOperationFlagsSaved; // our caller doesn't like us changing this
  208. ::FusionpSetLastWin32Error(dwLastError);
  209. }
  210. return fSuccess;
  211. }
  212. class CDllRedirAttemptInstallPolicies
  213. {
  214. public:
  215. CDllRedirAttemptInstallPolicies() { }
  216. ~CDllRedirAttemptInstallPolicies() { }
  217. CStringBuffer PoliciesRootPath;
  218. CStringBuffer PoliciesDestinationPath;
  219. WIN32_FIND_DATAW FindPolicyData;
  220. };
  221. BOOL
  222. CDllRedir::AttemptInstallPolicies(
  223. const CBaseStringBuffer &strTempRootSlash,
  224. const CBaseStringBuffer &moveDestination,
  225. const BOOL fReplaceExisting,
  226. OUT BOOL &fFoundPolicesToInstall
  227. )
  228. {
  229. BOOL fSuccess = FALSE;
  230. FN_TRACE_WIN32(fSuccess);
  231. CFindFile FindPolicies;
  232. CSmartPtr<CDllRedirAttemptInstallPolicies> Locals;
  233. IFW32FALSE_EXIT(Locals.Win32Allocate(__FILE__, __LINE__));
  234. CStringBuffer &PoliciesRootPath = Locals->PoliciesRootPath;
  235. CStringBuffer &PoliciesDestinationPath = Locals->PoliciesDestinationPath;
  236. WIN32_FIND_DATAW &FindPolicyData = Locals->FindPolicyData;
  237. SIZE_T cchRootBaseLength = 0;
  238. SIZE_T cchDestinationBaseLength = 0;
  239. fFoundPolicesToInstall = FALSE;
  240. // This is %installpath%\policies, turn it into %installpath%\policies\*
  241. IFW32FALSE_EXIT(PoliciesRootPath.Win32Assign(strTempRootSlash));
  242. IFW32FALSE_EXIT(PoliciesRootPath.Win32AppendPathElement(POLICY_ROOT_DIRECTORY_NAME, NUMBER_OF(POLICY_ROOT_DIRECTORY_NAME) - 1));
  243. IFW32FALSE_EXIT(PoliciesDestinationPath.Win32Assign(moveDestination));
  244. IFW32FALSE_EXIT(PoliciesDestinationPath.Win32AppendPathElement(POLICY_ROOT_DIRECTORY_NAME, NUMBER_OF(POLICY_ROOT_DIRECTORY_NAME) - 1));
  245. bool fExist = false;
  246. IFW32FALSE_EXIT(::SxspDoesFileExist(SXSP_DOES_FILE_EXIST_FLAG_CHECK_DIRECTORY_ONLY, PoliciesRootPath, fExist));
  247. if (!fExist)
  248. {
  249. #if DBG
  250. ::FusionpDbgPrintEx(FUSION_DBG_LEVEL_INFO,
  251. "SXS: %s() - No policies found (%ls not there), not attempting to install\n",
  252. __FUNCTION__,
  253. static_cast<PCWSTR>(PoliciesRootPath));
  254. #endif
  255. fSuccess = TRUE;
  256. goto Exit;
  257. }
  258. fFoundPolicesToInstall = TRUE;
  259. // Ensure that policies root always exists!
  260. IFW32FALSE_EXIT(PoliciesDestinationPath.Win32RemoveTrailingPathSeparators());
  261. IFW32FALSE_ORIGINATE_AND_EXIT(
  262. ::CreateDirectoryW(PoliciesDestinationPath, NULL) ||
  263. (::FusionpGetLastWin32Error() == ERROR_ALREADY_EXISTS));
  264. cchRootBaseLength = PoliciesRootPath.Cch();
  265. cchDestinationBaseLength = PoliciesDestinationPath.Cch();
  266. IFW32FALSE_EXIT(PoliciesRootPath.Win32AppendPathElement(L"*", 1));
  267. IFW32FALSE_EXIT(FindPolicies.Win32FindFirstFile(PoliciesRootPath, &FindPolicyData));
  268. do
  269. {
  270. if (::FusionpIsDotOrDotDot(FindPolicyData.cFileName))
  271. continue;
  272. if ((FindPolicyData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
  273. continue;
  274. // Generate %installtemp%\policies\{thisfoundpolicy}
  275. PoliciesRootPath.Left(cchRootBaseLength);
  276. PoliciesDestinationPath.Left(cchDestinationBaseLength);
  277. IFW32FALSE_EXIT(PoliciesRootPath.Win32AppendPathElement(FindPolicyData.cFileName, ::wcslen(FindPolicyData.cFileName)));
  278. IFW32FALSE_EXIT(PoliciesDestinationPath.Win32AppendPathElement(FindPolicyData.cFileName, ::wcslen(FindPolicyData.cFileName)));
  279. ::FusionpDbgPrintEx(FUSION_DBG_LEVEL_INFO,
  280. "SXS: %s():Found policy in staging area %ls\n\tMoving to %ls\n",
  281. __FUNCTION__,
  282. static_cast<PCWSTR>(PoliciesRootPath),
  283. static_cast<PCWSTR>(PoliciesDestinationPath));
  284. //
  285. // Ensure that the target path exists
  286. //
  287. IFW32FALSE_ORIGINATE_AND_EXIT(
  288. ::FusionpCreateDirectories(PoliciesDestinationPath, PoliciesDestinationPath.Cch()) ||
  289. (::FusionpGetLastWin32Error() == ERROR_ALREADY_EXISTS));
  290. //
  291. // Go copy files from the source path that we've consed up to the
  292. // target path that we've also consed up. Unfortunately, SxspMoveFilesUnderDir
  293. // does not actually return the buffers to the state they were in before
  294. // the call (they leave a trailing slash), so we have to manually use the size
  295. // thingy above (Left(originalsize)) to avoid this.
  296. //
  297. IFW32FALSE_EXIT(SxspMoveFilesUnderDir(
  298. 0,
  299. PoliciesRootPath,
  300. PoliciesDestinationPath,
  301. fReplaceExisting ? MOVEFILE_REPLACE_EXISTING : 0));
  302. }
  303. while(::FindNextFileW(FindPolicies, &FindPolicyData));
  304. if (::FusionpGetLastWin32Error() != ERROR_NO_MORE_FILES)
  305. {
  306. TRACE_WIN32_FAILURE_ORIGINATION(FindNextFileW);
  307. goto Exit;
  308. }
  309. ::SetLastError(ERROR_SUCCESS); // clear LastError
  310. IFW32FALSE_EXIT(FindPolicies.Win32Close());
  311. fSuccess = TRUE;
  312. Exit:
  313. return fSuccess;
  314. }
  315. class CDllRedirEndInstallLocals
  316. {
  317. public:
  318. CDllRedirEndInstallLocals() { }
  319. ~CDllRedirEndInstallLocals() { }
  320. CFusionDirectoryDifference directoryDifference;
  321. CStringBuffer tempStar; // also used for \winnt\winsxs\guid\foo
  322. WIN32_FIND_DATAW findData;
  323. CStringBuffer moveDestination; // \winnt\winsxs\foo
  324. };
  325. // NTRAID#NTBUG9 - 571863 - 2002/03/26 - xiaoyuw:
  326. // this function has two simliar blocks about moving files and moving manifest/cat,
  327. // it maybe replaced by SxspMoveFilesUnderDir
  328. //
  329. BOOL
  330. CDllRedir::EndInstall(
  331. PACTCTXCTB_CALLBACK_DATA Data
  332. )
  333. {
  334. BOOL fSuccess = FALSE;
  335. FN_TRACE_WIN32(fSuccess);
  336. /*
  337. 1) Make sure all the queued copies have actually been done.
  338. 2) Enumerate \winnt\winsxs\guid
  339. renaming each to be in \winnt\winsxs
  340. upon rename conflicts
  341. compare all the files in each (by size)
  342. output debug string if mismatch
  343. just leave temp if mismatch (will be cleaned up in common path)
  344. success either way
  345. 3) delete temp; delete runonce value
  346. */
  347. // make sure all the queued copies have actually been done
  348. const DWORD dwManifestOperationFlags = Data->Header.ManifestOperationFlags;
  349. const BOOL fVerify = (dwManifestOperationFlags & MANIFEST_OPERATION_INSTALL_FLAG_NO_VERIFY) == 0;
  350. const BOOL fTransactional = (dwManifestOperationFlags & MANIFEST_OPERATION_INSTALL_FLAG_NOT_TRANSACTIONAL) == 0;
  351. const BOOL fReplaceExisting = (dwManifestOperationFlags & MANIFEST_OPERATION_INSTALL_FLAG_REPLACE_EXISTING) != 0;
  352. const BOOL fAbort = (dwManifestOperationFlags & MANIFEST_OPERATION_INSTALL_FLAG_ABORT) != 0;
  353. BOOL fPoliciesExist = FALSE;
  354. HashValidateResult HashCorrect = HashValidate_OtherProblems;
  355. CFileStream * pLogFileStream = NULL;
  356. //
  357. // It'd be nice to skip the heap alloc in the abort case, but that
  358. // doesn't fit easily with our mechanical patterns..
  359. //
  360. CSmartPtr<CDllRedirEndInstallLocals> Locals;
  361. IFW32FALSE_EXIT(Locals.Win32Allocate(__FILE__, __LINE__));
  362. if (fAbort)
  363. {
  364. fSuccess = TRUE;
  365. goto Exit;
  366. }
  367. if (fVerify)
  368. {
  369. CQueuedFileCopies::ConstIterator i;
  370. for (i = m_queuedFileCopies.Begin() ; i != m_queuedFileCopies.End() ; ++i)
  371. {
  372. //
  373. // Only bother to check this if we're not in OS-setup mode.
  374. //
  375. if (i->m_bHasHashInfo)
  376. {
  377. IFW32FALSE_EXIT(::SxspCheckHashDuringInstall(i->m_bHasHashInfo, i->m_path, i->m_HashString, i->m_HashAlgorithm, HashCorrect));
  378. if (HashCorrect != HashValidate_Matches)
  379. {
  380. ::FusionpDbgPrintEx(
  381. FUSION_DBG_LEVEL_ERROR,
  382. "SXS: %s : SxspCheckHashDuringInstall(file=%ls)\n",
  383. __FUNCTION__,
  384. static_cast<PCWSTR>(i->m_path)
  385. );
  386. ORIGINATE_WIN32_FAILURE_AND_EXIT(FileHashDidNotMatchManifest, ERROR_SXS_FILE_HASH_MISMATCH);
  387. }
  388. }
  389. //
  390. // Otherwise, let's do the simple thing and just make sure the file made it
  391. //
  392. else
  393. {
  394. DWORD dwAttributes = ::GetFileAttributesW(i->m_path);
  395. if (dwAttributes == -1)
  396. {
  397. ::FusionpDbgPrintEx(
  398. FUSION_DBG_LEVEL_ERROR,
  399. "SXS: %s() GetFileAttributesW(%ls)\n",
  400. __FUNCTION__,
  401. static_cast<PCWSTR>(i->m_path));
  402. TRACE_WIN32_FAILURE_ORIGINATION(GetFileAttributesW);
  403. goto Exit;
  404. }
  405. }
  406. }
  407. }
  408. if (fTransactional)
  409. {
  410. CFusionDirectoryDifference &directoryDifference = Locals->directoryDifference;
  411. CFindFile findFile;
  412. CStringBuffer &tempStar = Locals->tempStar; // also used for \winnt\winsxs\guid\foo
  413. WIN32_FIND_DATAW &findData = Locals->findData;
  414. SIZE_T realRootSlashLength = 0; // length of "\winnt\winsxs\"
  415. SIZE_T tempRootSlashLength = 0; // length of "\winnt\winxsx\guid\"
  416. CStringBuffer &moveDestination = Locals->moveDestination; // \winnt\winsxs\foo
  417. IFW32FALSE_EXIT(::SxspGetAssemblyRootDirectory(moveDestination));
  418. IFW32FALSE_EXIT(moveDestination.Win32EnsureTrailingPathSeparator());
  419. realRootSlashLength = moveDestination.Cch();
  420. // move dirs from "\winnt\winsxs\InstallTemp\123456\" to \winnt\winsxs\x86_bar_1000_0409\"
  421. IFW32FALSE_EXIT(tempStar.Win32Assign(m_strTempRootSlash, m_strTempRootSlash.Cch()));
  422. tempRootSlashLength = tempStar.Cch();
  423. IFW32FALSE_EXIT(tempStar.Win32Append(L"*", 1));
  424. IFW32FALSE_EXIT(findFile.Win32FindFirstFile(tempStar, &findData));
  425. do
  426. {
  427. // skip . and ..
  428. if (::FusionpIsDotOrDotDot(findData.cFileName))
  429. continue;
  430. // there shouldn't be any files, skip them
  431. if ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY)
  432. continue;
  433. // skip manifests dir, do it at the second pass
  434. if (_wcsicmp(findData.cFileName, MANIFEST_ROOT_DIRECTORY_NAME) == 0) // in-casesensitive compare
  435. continue;
  436. if (_wcsicmp(findData.cFileName, POLICY_ROOT_DIRECTORY_NAME) == 0)
  437. continue;
  438. moveDestination.Left(realRootSlashLength);
  439. tempStar.Left(tempRootSlashLength);
  440. IFW32FALSE_EXIT(moveDestination.Win32Append(findData.cFileName, ::wcslen(findData.cFileName)));
  441. IFW32FALSE_EXIT(tempStar.Win32Append(findData.cFileName, ::wcslen(findData.cFileName)));
  442. //
  443. // replace existing doesn't work on directories, but we'll give it a shot anyway,
  444. // maybe it'll work in some future better version of Windows..
  445. // and of course, the error when you try this is "access denied" which is
  446. // somewhat unexpected, you have appro access to delete the directory maybe,
  447. // but not replace it.. the ReplaceFile api is also explicitly described
  448. // as for files only
  449. //
  450. IFW32FALSE_EXIT(::SxspInstallMoveFileExW(tempStar, moveDestination, fReplaceExisting? MOVEFILE_REPLACE_EXISTING : 0, TRUE));
  451. } while (::FindNextFileW(findFile, &findData));
  452. if (::FusionpGetLastWin32Error() != ERROR_NO_MORE_FILES)
  453. {
  454. ::FusionpDbgPrintEx(
  455. FUSION_DBG_LEVEL_ERROR,
  456. "SXS.DLL: %s(): FindNextFile() failed:%ld\n",
  457. __FUNCTION__,
  458. ::FusionpGetLastWin32Error());
  459. goto Exit;
  460. }
  461. if (!findFile.Win32Close())
  462. {
  463. ::FusionpDbgPrintEx(
  464. FUSION_DBG_LEVEL_ERROR,
  465. "SXS.DLL: %s(): FindClose() failed:%ld\n",
  466. __FUNCTION__,
  467. ::FusionpGetLastWin32Error());
  468. goto Exit;
  469. }
  470. // Honk off and install polices - fFoundPolicesToInstall will be true if we really found any.
  471. moveDestination.Left(realRootSlashLength);
  472. IFW32FALSE_EXIT(this->AttemptInstallPolicies(m_strTempRootSlash, moveDestination, fReplaceExisting, fPoliciesExist));
  473. // move manifest file from "\winnt\winsxs\InstallTemp\123456\manifests\x86_cards.2000_0409.manifest" to
  474. // \winnt\winsxs\manifests\x86_bar_1000_0406.manifst"
  475. moveDestination.Left(realRootSlashLength);
  476. IFW32FALSE_EXIT(moveDestination.Win32Append(MANIFEST_ROOT_DIRECTORY_NAME, NUMBER_OF(MANIFEST_ROOT_DIRECTORY_NAME) - 1));
  477. IFW32FALSE_EXIT(moveDestination.Win32EnsureTrailingPathSeparator()); //"winnt\winsxs\manifests\"
  478. realRootSlashLength = moveDestination.Cch();
  479. tempStar.Left(tempRootSlashLength);
  480. IFW32FALSE_EXIT(tempStar.Win32Append(MANIFEST_ROOT_DIRECTORY_NAME, NUMBER_OF(MANIFEST_ROOT_DIRECTORY_NAME) - 1));
  481. IFW32FALSE_EXIT(tempStar.Win32EnsureTrailingPathSeparator()); //"winnt\winsxs\InstallTemp\123456\manifests\"
  482. tempRootSlashLength = tempStar.Cch();
  483. IFW32FALSE_EXIT(tempStar.Win32Append(L"*", 1));
  484. IFW32FALSE_EXIT(findFile.Win32FindFirstFile(tempStar, &findData));
  485. do
  486. {
  487. // skip . and ..
  488. if (FusionpIsDotOrDotDot(findData.cFileName))
  489. continue;
  490. // there shouldn't be any directories, skip them
  491. if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  492. continue;
  493. moveDestination.Left(realRootSlashLength);
  494. tempStar.Left(tempRootSlashLength);
  495. IFW32FALSE_EXIT(moveDestination.Win32Append(findData.cFileName, ::wcslen(findData.cFileName)));
  496. IFW32FALSE_EXIT(tempStar.Win32Append(findData.cFileName, ::wcslen(findData.cFileName)));
  497. IFW32FALSE_EXIT(::SxspInstallMoveFileExW(tempStar, moveDestination, fReplaceExisting ? MOVEFILE_REPLACE_EXISTING : 0, TRUE));
  498. } while (::FindNextFileW(findFile, &findData));
  499. if (::FusionpGetLastWin32Error() != ERROR_NO_MORE_FILES)
  500. {
  501. ::FusionpDbgPrintEx(
  502. FUSION_DBG_LEVEL_ERROR,
  503. "SXS.DLL: %s(): FindNextFile() failed:%ld\n",
  504. __FUNCTION__,
  505. ::FusionpGetLastWin32Error());
  506. goto Exit;
  507. }
  508. if (!findFile.Win32Close())
  509. {
  510. ::FusionpDbgPrintEx(
  511. FUSION_DBG_LEVEL_ERROR,
  512. "SXS.DLL: %s(): FindClose() failed:%ld\n",
  513. __FUNCTION__,
  514. ::FusionpGetLastWin32Error());
  515. goto Exit;
  516. }
  517. }
  518. fSuccess = TRUE;
  519. Exit:
  520. if (pLogFileStream)
  521. {
  522. pLogFileStream->Close(); // ignore the error
  523. FUSION_DELETE_SINGLETON(pLogFileStream);
  524. }
  525. if (fTransactional)
  526. {
  527. DWORD dwLastError = ERROR_SUCCESS;
  528. if (!fSuccess)
  529. dwLastError = ::FusionpGetLastWin32Error();
  530. if (!m_strTempRootSlash.IsEmpty())
  531. {
  532. if (!SxspDeleteDirectory(m_strTempRootSlash))
  533. {
  534. ::FusionpDbgPrintEx(
  535. FUSION_DBG_LEVEL_ERROR,
  536. "SXS.DLL: %s(): SxspDeleteDirectory(%ls) failed:%ld\n",
  537. __FUNCTION__,
  538. static_cast<PCWSTR>(m_strTempRootSlash),
  539. ::FusionpGetLastWin32Error());
  540. if (fSuccess)
  541. {
  542. fSuccess = FALSE;
  543. dwLastError = ::FusionpGetLastWin32Error();
  544. }
  545. // Close instead of Cancel so the delete wil be tried again upon reboot
  546. if (m_pRunOnce != NULL && !m_pRunOnce->Close() && fSuccess)
  547. {
  548. dwLastError = ::FusionpGetLastWin32Error();
  549. fSuccess = FALSE;
  550. }
  551. }
  552. }
  553. if (m_pRunOnce != NULL && !m_pRunOnce->Cancel() && fSuccess)
  554. {
  555. dwLastError = ::FusionpGetLastWin32Error();
  556. fSuccess = FALSE;
  557. }
  558. if (!fSuccess)
  559. ::FusionpSetLastWin32Error(dwLastError);
  560. }
  561. m_pRunOnce = NULL;
  562. return fSuccess;
  563. }
  564. //
  565. // we have to do this in three places, so it is worth the reuse
  566. //
  567. class CMungeFileReadOnlynessAroundReplacement
  568. {
  569. public:
  570. #if POST_WHISTLER_BETA1
  571. CMungeFileReadOnlynessAroundReplacement()
  572. : m_ReplaceExisting(false), m_FileAttributes(SXSP_INVALID_FILE_ATTRIBUTES)
  573. {
  574. }
  575. BOOL Initialize(
  576. const CBaseStringBuffer &rbuff,
  577. BOOL ReplaceExisting
  578. )
  579. {
  580. BOOL Success = FALSE;
  581. FN_TRACE_WIN32(Success);
  582. IFW32FALSE_EXIT(m_FileName.Win32Assign(rbuff));
  583. m_ReplaceExisting = ReplaceExisting;
  584. // deliberately ignore failure from GetFileAttributes
  585. // 1) It's ok if the file doesn't exist
  586. // 2) If there's a more serious problem, we'll hit it again immediately, but
  587. // that does lead to nested retry.
  588. m_FileAttributes = (ReplaceExisting ? ::GetFileAttributesW(FileName) : SXSP_INVALID_FILE_ATTRIBUTES);
  589. if (m_FileAttributes != SXSP_INVALID_FILE_ATTRIBUTES)
  590. ::SetFileAttributesW(FileName, 0);
  591. Success = TRUE;
  592. Exit:
  593. return Success;
  594. }
  595. ~CMungeFileReadOnlynessAroundReplacement()
  596. {
  597. if (m_ReplaceExisting && m_FileAttributes != SXSP_INVALID_FILE_ATTRIBUTES)
  598. {
  599. // error deliberately ignored
  600. SXSP_PRESERVE_LAST_ERROR(::SetFileAttributesW(m_FileName, m_FileAttributes));
  601. }
  602. }
  603. BOOL m_ReplaceExisting;
  604. CUnicodeStringBuffer m_FileName;
  605. DWORD m_FileAttributes;
  606. #else // POST_WHISTLER_BETA1
  607. // simpler code for beta1
  608. BOOL Initialize(
  609. PCWSTR FileName,
  610. BOOL /*ReplaceExisting*/
  611. )
  612. {
  613. // error deliberately ignored
  614. ::SetFileAttributesW(FileName, 0);
  615. return TRUE;
  616. }
  617. #endif // POST_WHISTLER_BETA1
  618. };
  619. class CDllRedirInstallCatalogLocals
  620. {
  621. public:
  622. CDllRedirInstallCatalogLocals() { }
  623. ~CDllRedirInstallCatalogLocals() { }
  624. CMungeFileReadOnlynessAroundReplacement MungeCatalogAttributes;
  625. CStringBuffer CatalogSourceBuffer;
  626. CStringBuffer CatalogDestinationBuffer;
  627. CPublicKeyInformation CatalogSignerInfo;
  628. CSmallStringBuffer sbStrongNameString;
  629. CSmallStringBuffer sbReferencePublicKeyToken;
  630. CSmallStringBuffer sbSignerName;
  631. };
  632. BOOL
  633. CDllRedir::InstallCatalog(
  634. DWORD dwManifestOperationFlags,
  635. const CBaseStringBuffer &ManifestSourceBuffer,
  636. const CBaseStringBuffer &ManifestDestinationBuffer,
  637. PCACTCTXCTB_ASSEMBLY_CONTEXT AssemblyContext
  638. )
  639. {
  640. BOOL fSuccess = FALSE;
  641. FN_TRACE_WIN32(fSuccess);
  642. bool fHasCatalog = false;
  643. CSmartPtr<CDllRedirInstallCatalogLocals> Locals;
  644. IFW32FALSE_EXIT(Locals.Win32Allocate(__FILE__, __LINE__));
  645. CMungeFileReadOnlynessAroundReplacement &MungeCatalogAttributes = Locals->MungeCatalogAttributes;
  646. CStringBuffer &CatalogSourceBuffer = Locals->CatalogSourceBuffer;
  647. CStringBuffer &CatalogDestinationBuffer = Locals->CatalogDestinationBuffer;
  648. ManifestValidationResult ManifestStatus = ManifestValidate_Unknown;
  649. BOOL fAreWeInOSSetupMode = FALSE;
  650. BOOL bInstallCatalogSuccess = FALSE;
  651. //
  652. // Determine the possible source and destination of the catalog file. This
  653. // needs to be done, even if we're not explicitly looking for a catalog, since
  654. // our heuristic still needs to check to see if there is one available.
  655. //
  656. IFW32FALSE_EXIT(CatalogDestinationBuffer.Win32Assign(ManifestDestinationBuffer));
  657. IFW32FALSE_EXIT(CatalogDestinationBuffer.Win32ChangePathExtension(FILE_EXTENSION_CATALOG, FILE_EXTENSION_CATALOG_CCH, eAddIfNoExtension));
  658. IFW32FALSE_EXIT(CatalogSourceBuffer.Win32Assign(ManifestSourceBuffer));
  659. IFW32FALSE_EXIT(CatalogSourceBuffer.Win32ChangePathExtension(FILE_EXTENSION_CATALOG, FILE_EXTENSION_CATALOG_CCH, eAddIfNoExtension));
  660. //
  661. // Note: We only attempt to deal with catalogs when there is installation info.
  662. // Even if there was no install data, we don't bother looking to see if there's
  663. // a catalog. Catalogs imply signatures and public key information, and require
  664. // a codebase to be reinstalled from. If you didn't provide such to the installer,
  665. // shame on you.
  666. //
  667. if ((dwManifestOperationFlags & MANIFEST_OPERATION_INSTALL_FLAG_FORCE_LOOK_FOR_CATALOG) != 0)
  668. {
  669. //
  670. // If they insist.
  671. //
  672. IFW32FALSE_EXIT(::SxspDoesFileExist(SXSP_DOES_FILE_EXIST_FLAG_COMPRESSION_AWARE, CatalogSourceBuffer, fHasCatalog));
  673. }
  674. else if (AssemblyContext->InstallationInfo != NULL)
  675. {
  676. PSXS_INSTALL_SOURCE_INFO pInfo = static_cast<PSXS_INSTALL_SOURCE_INFO>(AssemblyContext->InstallationInfo);
  677. ::FusionpDbgPrintEx(
  678. FUSION_DBG_LEVEL_INSTALLATION,
  679. "SXS.DLL: %s() found installation info at %p\n"
  680. " pInfo->dwFlags = 0x%08lx\n",
  681. __FUNCTION__, pInfo, (pInfo != NULL) ? pInfo->dwFlags : 0);
  682. //
  683. // Do we explicitly have a catalog?
  684. //
  685. fHasCatalog = ((pInfo->dwFlags & SXSINSTALLSOURCE_HAS_CATALOG) != 0);
  686. if (fHasCatalog)
  687. {
  688. FusionpDbgPrintEx(
  689. FUSION_DBG_LEVEL_INSTALLATION,
  690. "SXS.DLL: Using catalog because install source says that they're supposed to be there.\n");
  691. }
  692. //
  693. // Well, if we didn't, then we still should look.. maybe they forgot the flag.
  694. // But, only look if they don't mind us checking.
  695. //
  696. if (!(pInfo->dwFlags & SXSINSTALLSOURCE_DONT_DETECT_CATALOG) && !fHasCatalog)
  697. IFW32FALSE_EXIT(::SxspDoesFileExist(SXSP_DOES_FILE_EXIST_FLAG_COMPRESSION_AWARE, CatalogSourceBuffer, fHasCatalog));
  698. pInfo->dwFlags |= (fHasCatalog ? SXSINSTALLSOURCE_HAS_CATALOG : 0);
  699. }
  700. if (!fHasCatalog)
  701. {
  702. ::FusionpLogError(
  703. MSG_SXS_PUBLIC_ASSEMBLY_REQUIRES_CATALOG_AND_SIGNATURE,
  704. CEventLogString(ManifestSourceBuffer));
  705. ::FusionpSetLastWin32Error(ERROR_SXS_PROTECTION_CATALOG_FILE_MISSING);
  706. goto Exit;
  707. }
  708. //
  709. // If there's no catalog present, then something bad happened
  710. // at some point along the way - fail the installation!
  711. //
  712. // Copyfile it over. We do this rather than streaming because we don't
  713. // care about the contents of the catalog, it's binary.
  714. //
  715. IFW32FALSE_EXIT(MungeCatalogAttributes.Initialize(CatalogDestinationBuffer, TRUE));
  716. if (dwManifestOperationFlags & MANIFEST_OPERATION_INSTALL_FLAG_MOVE)
  717. {
  718. bInstallCatalogSuccess = ::SxspInstallDecompressAndMoveFileExW(
  719. CatalogSourceBuffer,
  720. CatalogDestinationBuffer,
  721. (dwManifestOperationFlags & MANIFEST_OPERATION_INSTALL_FLAG_REPLACE_EXISTING) ? MOVEFILE_REPLACE_EXISTING : 0);
  722. }
  723. else
  724. {
  725. bInstallCatalogSuccess =
  726. ::SxspInstallDecompressOrCopyFileW(
  727. CatalogSourceBuffer,
  728. CatalogDestinationBuffer,
  729. (dwManifestOperationFlags & MANIFEST_OPERATION_INSTALL_FLAG_REPLACE_EXISTING) ? FALSE : TRUE); // bFailIfExist == FALSE
  730. }
  731. if (!bInstallCatalogSuccess)
  732. {
  733. #if DBG
  734. ::FusionpDbgPrintEx(
  735. FUSION_DBG_LEVEL_ERROR,
  736. "SXS.DLL:%s Failed DecompressOrCopying catalog file from [%ls] to [%ls] - Error was 0x%08x\n",
  737. __FUNCTION__,
  738. static_cast<PCWSTR>(CatalogSourceBuffer),
  739. static_cast<PCWSTR>(CatalogDestinationBuffer),
  740. ::FusionpGetLastWin32Error());
  741. #endif
  742. TRACE_WIN32_FAILURE_ORIGINATION(SxspInstallDecompressOrCopyFileW);
  743. goto Exit;
  744. }
  745. //
  746. // If we're in OS-setup mode, then we don't bother to validate this manifest against
  747. // its catalog, instead assuming that the catalogs coming off the CD/installpoint
  748. // are golden. This does not protect us against malicious IT managers, warezer groups
  749. // putting bad bits in their distros, etc. But who cares, right?
  750. //
  751. IFW32FALSE_EXIT(::FusionpAreWeInOSSetupMode(&fAreWeInOSSetupMode));
  752. if (!fAreWeInOSSetupMode && fHasCatalog)
  753. {
  754. ULONG ulCatalogKeyLength = 0;
  755. CPublicKeyInformation &CatalogSignerInfo = Locals->CatalogSignerInfo;
  756. CSmallStringBuffer &sbStrongNameString = Locals->sbStrongNameString;
  757. CSmallStringBuffer &sbReferencePublicKeyToken = Locals->sbReferencePublicKeyToken;
  758. BOOL bHasPublicKeyToken = FALSE;
  759. BOOL bStrongNameMatches = FALSE;
  760. CAssemblyReference OurReference;
  761. IFW32FALSE_EXIT(OurReference.Initialize(AssemblyContext->AssemblyIdentity));
  762. IFW32FALSE_EXIT(OurReference.GetPublicKeyToken(&sbReferencePublicKeyToken, bHasPublicKeyToken));
  763. //
  764. // Validate the catalog and manifest, but don't check the strong name
  765. // yet - the file name isn't valid at this point.
  766. //
  767. IFW32FALSE_EXIT(::SxspValidateManifestAgainstCatalog(
  768. ManifestDestinationBuffer,
  769. CatalogDestinationBuffer,
  770. ManifestStatus,
  771. MANIFESTVALIDATE_MODE_NO_STRONGNAME));
  772. //
  773. // If there's no catalog, or there is a catalog but it's broken, then
  774. // we need to complain and exit.
  775. //
  776. if (ManifestStatus != ManifestValidate_IsIntact)
  777. {
  778. #if DBG
  779. DWORD dwFileAttributes = 0;
  780. ::FusionpDbgPrintEx(FUSION_DBG_LEVEL_ERROR,
  781. "SXS: ManifestStatus: %s (%lu)\n",
  782. SxspManifestValidationResultToString(ManifestStatus),
  783. static_cast<ULONG>(ManifestStatus));
  784. dwFileAttributes = ::GetFileAttributesW(ManifestSourceBuffer);
  785. if (dwFileAttributes == INVALID_FILE_ATTRIBUTES)
  786. ::FusionpDbgPrintEx(FUSION_DBG_LEVEL_ERROR,
  787. "SXS: GetFileAttributes(%ls):0x%lx, error:%lu\n",
  788. static_cast<PCWSTR>(ManifestSourceBuffer),
  789. dwFileAttributes,
  790. ::FusionpGetLastWin32Error());
  791. dwFileAttributes = ::GetFileAttributesW(CatalogDestinationBuffer);
  792. if (dwFileAttributes == INVALID_FILE_ATTRIBUTES)
  793. ::FusionpDbgPrintEx(FUSION_DBG_LEVEL_ERROR,
  794. "SXS: GetFileAttribtes(%ls):0x%lx, error:%lu\n",
  795. static_cast<PCWSTR>(CatalogDestinationBuffer),
  796. dwFileAttributes,
  797. ::FusionpGetLastWin32Error());
  798. #endif
  799. ::FusionpLogError(
  800. MSG_SXS_MANIFEST_CATALOG_VERIFY_FAILURE,
  801. CEventLogString(ManifestDestinationBuffer));
  802. ::FusionpSetLastWin32Error(ERROR_SXS_PROTECTION_CATALOG_NOT_VALID);
  803. goto Exit;
  804. }
  805. //
  806. // Get some useful information about the catalog's signer - opens the catalog
  807. // on the installation source.
  808. //
  809. IFW32FALSE_EXIT(CatalogSignerInfo.Initialize(CatalogDestinationBuffer));
  810. IFW32FALSE_EXIT(CatalogSignerInfo.GetPublicKeyBitLength(ulCatalogKeyLength));
  811. //
  812. // Minimally, we need some number of bits in the signing catalog's public key
  813. //
  814. if ((ulCatalogKeyLength < SXS_MINIMAL_SIGNING_KEY_LENGTH) || !bHasPublicKeyToken)
  815. {
  816. CSmallStringBuffer &sbSignerName = Locals->sbSignerName;
  817. sbSignerName.Clear();
  818. IFW32FALSE_EXIT(CatalogSignerInfo.GetSignerNiceName(sbSignerName));
  819. ::FusionpLogError(
  820. MSG_SXS_CATALOG_SIGNER_KEY_TOO_SHORT,
  821. CEventLogString(sbSignerName),
  822. CEventLogString(CatalogSourceBuffer));
  823. goto Exit;
  824. }
  825. // Now compare the public key tokens
  826. IFW32FALSE_EXIT(CatalogSignerInfo.DoesStrongNameMatchSigner(sbReferencePublicKeyToken, bStrongNameMatches));
  827. if (!bStrongNameMatches)
  828. {
  829. CSmallStringBuffer &sbSignerName = Locals->sbSignerName;
  830. sbSignerName.Clear();
  831. IFW32FALSE_EXIT(CatalogSignerInfo.GetSignerNiceName(sbSignerName));
  832. ::FusionpLogError(
  833. MSG_SXS_PUBLIC_KEY_TOKEN_AND_CATALOG_MISMATCH,
  834. CEventLogString(CatalogSourceBuffer),
  835. CEventLogString(sbSignerName),
  836. CEventLogString(sbReferencePublicKeyToken));
  837. goto Exit;
  838. }
  839. }
  840. fSuccess = TRUE;
  841. Exit:
  842. return fSuccess;
  843. }
  844. class CDllRedirInstallManifestLocals
  845. {
  846. public:
  847. CDllRedirInstallManifestLocals() { }
  848. ~CDllRedirInstallManifestLocals() { }
  849. CStringBuffer ManifestSourceBuffer;
  850. CStringBuffer ManifestDestinationBuffer;
  851. CStringBuffer ManifestFileNameBuffer;
  852. CStringBuffer CatalogSourceBuffer;
  853. CStringBuffer CatalogDestinationBuffer;
  854. };
  855. BOOL
  856. CDllRedir::InstallManifest(
  857. DWORD dwManifestOperationFlags,
  858. PCACTCTXCTB_ASSEMBLY_CONTEXT AssemblyContext
  859. )
  860. {
  861. FN_PROLOG_WIN32
  862. BOOL fVerify = FALSE;
  863. BOOL fTransactional = FALSE;
  864. BOOL fReplaceExisting = FALSE;
  865. BOOL fIsSetupTime = FALSE;
  866. DWORD OpenOrCreateManifestDestination;
  867. CTeeStream* TeeStreamForManifestInstall = NULL;
  868. CFullPathSplitPointers SplitManifestSource;
  869. CMungeFileReadOnlynessAroundReplacement MungeManifestAttributes;
  870. CAssemblyReference TempAssemblyReference;
  871. //
  872. // Windows Setup is restartable, so we must be too when it calls us.
  873. // ReplaceExisting is probably enough to use CREATE_ALWAYS, but lets be safer for
  874. // now and check both weakenings.
  875. //
  876. CSmartPtr<CDllRedirInstallManifestLocals> Locals;
  877. IFW32FALSE_EXIT(Locals.Win32Allocate(__FILE__, __LINE__));
  878. CStringBuffer &ManifestSourceBuffer = Locals->ManifestSourceBuffer;
  879. CStringBuffer &ManifestDestinationBuffer = Locals->ManifestDestinationBuffer;
  880. CStringBuffer &ManifestFileNameBuffer = Locals->ManifestFileNameBuffer;
  881. CStringBuffer &CatalogSourceBuffer = Locals->CatalogSourceBuffer;
  882. CStringBuffer &CatalogDestinationBuffer = Locals->CatalogDestinationBuffer;
  883. fVerify = (dwManifestOperationFlags & MANIFEST_OPERATION_INSTALL_FLAG_NO_VERIFY) == 0;
  884. fTransactional = (dwManifestOperationFlags & MANIFEST_OPERATION_INSTALL_FLAG_NOT_TRANSACTIONAL) == 0;
  885. fReplaceExisting = (dwManifestOperationFlags & MANIFEST_OPERATION_INSTALL_FLAG_REPLACE_EXISTING) != 0;
  886. OpenOrCreateManifestDestination = (fReplaceExisting && !fTransactional) ? CREATE_ALWAYS : CREATE_NEW;
  887. TeeStreamForManifestInstall = reinterpret_cast<CTeeStream*>(AssemblyContext->TeeStreamForManifestInstall);
  888. const bool fIsSystemPolicyInstallation =
  889. (AssemblyContext->Flags & ACTCTXCTB_ASSEMBLY_CONTEXT_IS_SYSTEM_POLICY_INSTALLATION) != 0;
  890. #if FUSION_PRECOMPILED_MANIFEST
  891. CMungeFileReadOnlynessAroundReplacement MungePrecompiledManifestAttributes;
  892. CPrecompiledManifestWriterStream * pcmWriterStream = reinterpret_cast<CPrecompiledManifestWriterStream *>(AssemblyContext->pcmWriterStream);
  893. #endif
  894. PARAMETER_CHECK(AssemblyContext != NULL);
  895. INTERNAL_ERROR_CHECK(AssemblyContext->TeeStreamForManifestInstall != NULL);
  896. // Get "\windir\winsxs\install\guid\manifests" or Get "\windir\winsxs\install\guid\policies".
  897. IFW32FALSE_EXIT(
  898. ::SxspGenerateSxsPath(
  899. SXSP_GENERATE_SXS_PATH_FLAG_PARTIAL_PATH, // Flags
  900. fIsSystemPolicyInstallation ? SXSP_GENERATE_SXS_PATH_PATHTYPE_POLICY : SXSP_GENERATE_SXS_PATH_PATHTYPE_MANIFEST,
  901. m_strTempRootSlash,
  902. m_strTempRootSlash.Cch(),
  903. AssemblyContext->AssemblyIdentity,
  904. NULL,
  905. ManifestDestinationBuffer));
  906. // remove the trailing slash because CreateDirectory maybe sometimes doesn't like it
  907. IFW32FALSE_EXIT(ManifestDestinationBuffer.Win32RemoveTrailingPathSeparators());
  908. IFW32FALSE_ORIGINATE_AND_EXIT(
  909. ::CreateDirectoryW(ManifestDestinationBuffer, NULL)
  910. || ::FusionpGetLastWin32Error() == ERROR_ALREADY_EXISTS);
  911. IFW32FALSE_EXIT(ManifestSourceBuffer.Win32Assign(AssemblyContext->ManifestPath, AssemblyContext->ManifestPathCch));
  912. // get "x86_bar_1000_0409"
  913. IFW32FALSE_EXIT(
  914. ::SxspGenerateSxsPath(
  915. SXSP_GENERATE_SXS_PATH_FLAG_OMIT_ROOT
  916. | (fIsSystemPolicyInstallation ? SXSP_GENERATE_SXS_PATH_FLAG_OMIT_VERSION : 0),
  917. SXSP_GENERATE_SXS_PATH_PATHTYPE_ASSEMBLY,
  918. m_strTempRootSlash,
  919. m_strTempRootSlash.Cch(),
  920. AssemblyContext->AssemblyIdentity,
  921. NULL,
  922. ManifestFileNameBuffer));
  923. // create policies\x86_policy.6.0.Microsoft.windows.cards_pulicKeyToken_en-us_1223423423
  924. IFW32FALSE_EXIT(ManifestDestinationBuffer.Win32AppendPathElement(ManifestFileNameBuffer));
  925. if (fIsSystemPolicyInstallation)
  926. {
  927. PCWSTR pszVersion = NULL;
  928. SIZE_T VersionCch = 0;
  929. // for policy installation, create a subdir under Policies
  930. IFW32FALSE_ORIGINATE_AND_EXIT(
  931. ::CreateDirectoryW(ManifestDestinationBuffer, NULL)
  932. || ::FusionpGetLastWin32Error() == ERROR_ALREADY_EXISTS);
  933. //generate policy file name, like 1.0.0.0.policy
  934. IFW32FALSE_EXIT(
  935. ::SxspGetAssemblyIdentityAttributeValue(
  936. SXSP_GET_ASSEMBLY_IDENTITY_ATTRIBUTE_VALUE_FLAG_NOT_FOUND_RETURNS_NULL,
  937. AssemblyContext->AssemblyIdentity,
  938. &s_IdentityAttribute_version,
  939. &pszVersion,
  940. &VersionCch));
  941. INTERNAL_ERROR_CHECK(VersionCch != 0);
  942. IFW32FALSE_EXIT(ManifestDestinationBuffer.Win32EnsureTrailingPathSeparator());
  943. IFW32FALSE_EXIT(ManifestDestinationBuffer.Win32Append(pszVersion, VersionCch));
  944. // .policy
  945. IFW32FALSE_EXIT(ManifestDestinationBuffer.Win32Append(ASSEMBLY_POLICY_FILE_NAME_SUFFIX_POLICY, NUMBER_OF(ASSEMBLY_POLICY_FILE_NAME_SUFFIX_POLICY) - 1));
  946. }
  947. else
  948. {
  949. // .manifest
  950. IFW32FALSE_EXIT(ManifestDestinationBuffer.Win32RemoveTrailingPathSeparators());
  951. IFW32FALSE_EXIT(ManifestDestinationBuffer.Win32Append(ASSEMBLY_MANIFEST_FILE_NAME_SUFFIX_MANIFEST, NUMBER_OF(ASSEMBLY_MANIFEST_FILE_NAME_SUFFIX_MANIFEST) - 1));
  952. }
  953. IFW32FALSE_EXIT(MungeManifestAttributes.Initialize(ManifestDestinationBuffer, fReplaceExisting));
  954. //
  955. // Set the manifest sink before trying to install the catalog, so that if the source is a binary, that is, the manifest is from
  956. // a dll or exe, we could check the catalog with the manifest .
  957. //
  958. IFW32FALSE_EXIT(TeeStreamForManifestInstall->SetSink(ManifestDestinationBuffer, OpenOrCreateManifestDestination));
  959. IFW32FALSE_EXIT(TeeStreamForManifestInstall->Close());
  960. //
  961. // Try installing the catalog that goes with this assembly
  962. //
  963. IFW32FALSE_EXIT(
  964. this->InstallCatalog(
  965. dwManifestOperationFlags,
  966. ManifestSourceBuffer,
  967. ManifestDestinationBuffer,
  968. AssemblyContext));
  969. ::FusionpDbgPrintEx(
  970. FUSION_DBG_LEVEL_INSTALLATION,
  971. "SXS.DLL: Sinking manifest to \"%S\"\n", static_cast<PCWSTR>(ManifestDestinationBuffer));
  972. #if FUSION_PRECOMPILED_MANIFEST
  973. IFW32FALSE_EXIT(
  974. ManifestDestinationBuffer.Win32ChangePathExtension(
  975. PRECOMPILED_MANIFEST_EXTENSION,
  976. NUMBER_OF(PRECOMPILED_MANIFEST_EXTENSION) - 1,
  977. NULL,
  978. eErrorIfNoExtension));
  979. IFW32FALSE_EXIT(MungePrecompiledManifestAttributes.Initialize(ManifestDestinationBuffer, fReplaceExisting));
  980. IFW32FALSE_EXIT(pcmWriterStream->SetSink(ManifestDestinationBuffer, OpenOrCreateManifestDestination));
  981. #endif
  982. //
  983. // Now, if we're in setup mode and we're installing a policy file, then
  984. // also stream the file out, then also CopyFile the file out to a SetupPolicies in the target path
  985. // as well.
  986. //
  987. // Side notes: We don't try to copy the catalog next to the manifest, since there's no
  988. // WFP happening during setup. We can simply skip this bit. We also don't bother
  989. // registering this manifest in the registry anywhere, for the same reason. Once setup
  990. // completes, we'll poof the %windir%\winsxs\setuppolicies directory (and friends)
  991. // as part of tearing down the ~ls directory.
  992. //
  993. IFW32FALSE_EXIT(::FusionpAreWeInOSSetupMode(&fIsSetupTime));
  994. if (fIsSetupTime && fIsSystemPolicyInstallation)
  995. {
  996. PCWSTR pszVersion = NULL;
  997. SIZE_T VersionCch = 0;
  998. //
  999. // Let's reuse the manifest destination buffer.
  1000. //
  1001. IFW32FALSE_EXIT(::SxspGenerateSxsPath(
  1002. SXSP_GENERATE_SXS_PATH_FLAG_PARTIAL_PATH,
  1003. SXSP_GENERATE_SXS_PATH_PATHTYPE_SETUP_POLICY,
  1004. this->m_strTempRootSlash,
  1005. this->m_strTempRootSlash.Cch(),
  1006. AssemblyContext->AssemblyIdentity,
  1007. NULL,
  1008. ManifestDestinationBuffer));
  1009. //
  1010. // Ensure the destination path exists
  1011. //
  1012. IFW32FALSE_EXIT(::SxspCreateMultiLevelDirectory(
  1013. this->m_strTempRootSlash,
  1014. SETUP_POLICY_ROOT_DIRECTORY_NAME));
  1015. //
  1016. //generate policy file name, like 1.0.0.0.policy
  1017. //
  1018. IFW32FALSE_EXIT(::SxspGetAssemblyIdentityAttributeValue(
  1019. SXSP_GET_ASSEMBLY_IDENTITY_ATTRIBUTE_VALUE_FLAG_NOT_FOUND_RETURNS_NULL,
  1020. AssemblyContext->AssemblyIdentity,
  1021. &s_IdentityAttribute_version,
  1022. &pszVersion,
  1023. &VersionCch));
  1024. IFW32FALSE_EXIT(ManifestDestinationBuffer.Win32AppendPathElement(ManifestFileNameBuffer));
  1025. //
  1026. // Create directory
  1027. //
  1028. IFW32FALSE_EXIT(
  1029. ::CreateDirectoryW(ManifestDestinationBuffer, NULL) ||
  1030. (::FusionpGetLastWin32Error() == ERROR_ALREADY_EXISTS));
  1031. INTERNAL_ERROR_CHECK(VersionCch != 0);
  1032. IFW32FALSE_EXIT(ManifestDestinationBuffer.Win32EnsureTrailingPathSeparator());
  1033. IFW32FALSE_EXIT(ManifestDestinationBuffer.Win32Append(pszVersion, VersionCch));
  1034. IFW32FALSE_EXIT(ManifestDestinationBuffer.Win32Append(ASSEMBLY_POLICY_FILE_NAME_SUFFIX_POLICY, NUMBER_OF(ASSEMBLY_POLICY_FILE_NAME_SUFFIX_POLICY) - 1));
  1035. //
  1036. // And copy the file over (replace an existing one, it might be bogus!)
  1037. //
  1038. // Attention: manifest is never been compressed, and it is easy to replace SxspCopyFile with SetupDecompressOrCopyFile
  1039. //
  1040. IFW32FALSE_EXIT(SxspCopyFile(
  1041. SXSP_COPY_FILE_FLAG_REPLACE_EXISTING,
  1042. ManifestSourceBuffer,
  1043. ManifestDestinationBuffer));
  1044. }
  1045. FN_EPILOG
  1046. }
  1047. class CDllRedirInstallFileLocals
  1048. {
  1049. public:
  1050. CDllRedirInstallFileLocals() { }
  1051. ~CDllRedirInstallFileLocals() { }
  1052. CStringBuffer SourceBuffer;
  1053. CStringBuffer DestinationBuffer;
  1054. CStringBuffer SourceFileNameBuffer;
  1055. CStringBuffer HashDataString;
  1056. CSmallStringBuffer HashAlgNiceName;
  1057. CFusionFilePathAndSize verifyQueuedFileCopy;
  1058. CStringBuffer DestinationDirectory;
  1059. CMungeFileReadOnlynessAroundReplacement MungeFileAttributes;
  1060. CStringBuffer renameExistingAway;
  1061. CSmallStringBuffer uidBuffer;
  1062. };
  1063. BOOL
  1064. CDllRedir::InstallFile(
  1065. PACTCTXCTB_CALLBACK_DATA Data,
  1066. const CBaseStringBuffer &FileNameBuffer
  1067. )
  1068. {
  1069. BOOL fSuccess = FALSE;
  1070. FN_TRACE_WIN32(fSuccess);
  1071. CSmartPtr<CDllRedirInstallFileLocals> Locals;
  1072. IFW32FALSE_EXIT(Locals.Win32Allocate(__FILE__, __LINE__));
  1073. CStringBuffer &SourceBuffer = Locals->SourceBuffer;
  1074. CStringBuffer &DestinationBuffer = Locals->DestinationBuffer;
  1075. SIZE_T DirectoryLength = 0;
  1076. CStringBuffer &SourceFileNameBuffer = Locals->SourceFileNameBuffer;
  1077. ULONGLONG SourceFileSize = 0;
  1078. bool fFound = false;
  1079. SIZE_T cb = 0;
  1080. ULONG Disposition = (Data->Header.ManifestOperationFlags & MANIFEST_OPERATION_INSTALL_FLAG_MOVE) ? SXS_INSTALLATION_FILE_COPY_DISPOSITION_PLEASE_MOVE : SXS_INSTALLATION_FILE_COPY_DISPOSITION_PLEASE_COPY;
  1081. const DWORD dwManifestOperationFlags = Data->Header.ManifestOperationFlags;
  1082. const BOOL fVerify = (dwManifestOperationFlags & MANIFEST_OPERATION_INSTALL_FLAG_NO_VERIFY) == 0;
  1083. const BOOL fTransactional = (dwManifestOperationFlags & MANIFEST_OPERATION_INSTALL_FLAG_NOT_TRANSACTIONAL) == 0;
  1084. const BOOL fReplaceExisting = (dwManifestOperationFlags & MANIFEST_OPERATION_INSTALL_FLAG_REPLACE_EXISTING) != 0;
  1085. ALG_ID HashAlgId = FUSION_DEFAULT_HASH_ALGORITHM;
  1086. bool fHasHashData = false;
  1087. bool fHasHashAlgName = false;
  1088. HashValidateResult HashCorrect = HashValidate_OtherProblems;
  1089. CStringBuffer &HashDataString = Locals->HashDataString;
  1090. CSmallStringBuffer &HashAlgNiceName = Locals->HashAlgNiceName;
  1091. IFW32FALSE_EXIT(
  1092. ::SxspGenerateSxsPath(
  1093. 0, // Flags
  1094. SXSP_GENERATE_SXS_PATH_PATHTYPE_ASSEMBLY,
  1095. m_strTempRootSlash,
  1096. m_strTempRootSlash.Cch(),
  1097. Data->ElementParsed.AssemblyContext->AssemblyIdentity,
  1098. NULL,
  1099. DestinationBuffer));
  1100. IFW32FALSE_EXIT(DestinationBuffer.Win32Append(static_cast<PCWSTR>(FileNameBuffer), FileNameBuffer.Cch()));
  1101. DirectoryLength = 1 + DestinationBuffer.CchWithoutLastPathElement();
  1102. // Take the manifest path, trim back to the directory name and add the file...
  1103. IFW32FALSE_EXIT(SourceBuffer.Win32Assign(Data->ElementParsed.AssemblyContext->ManifestPath, Data->ElementParsed.AssemblyContext->ManifestPathCch));
  1104. IFW32FALSE_EXIT(SourceBuffer.Win32RemoveLastPathElement());
  1105. IFW32FALSE_EXIT(
  1106. ::SxspGetAttributeValue(
  1107. 0,
  1108. &s_AttributeName_sourceName,
  1109. &Data->ElementParsed,
  1110. fFound,
  1111. sizeof(SourceFileNameBuffer),
  1112. &SourceFileNameBuffer,
  1113. cb,
  1114. NULL,
  1115. 0));
  1116. PCWSTR SourceFileName;
  1117. if (fFound)
  1118. SourceFileName = SourceFileNameBuffer;
  1119. else
  1120. SourceFileName = FileNameBuffer;
  1121. // Extract information about the hashing stuff that's included on this node
  1122. IFW32FALSE_EXIT(
  1123. ::SxspGetAttributeValue(
  1124. 0,
  1125. &s_AttributeName_hash,
  1126. &Data->ElementParsed,
  1127. fHasHashData,
  1128. sizeof(HashDataString),
  1129. &HashDataString,
  1130. cb,
  1131. NULL,
  1132. 0));
  1133. IFW32FALSE_EXIT(
  1134. ::SxspGetAttributeValue(
  1135. 0,
  1136. &s_AttributeName_hashalg,
  1137. &Data->ElementParsed,
  1138. fHasHashAlgName,
  1139. sizeof(HashAlgNiceName),
  1140. &HashAlgNiceName,
  1141. cb,
  1142. NULL,
  1143. 0));
  1144. //
  1145. // Neat. Find out what the hash algorithm was.
  1146. //
  1147. if (fHasHashAlgName)
  1148. {
  1149. if (!::SxspHashAlgFromString(HashAlgNiceName, HashAlgId))
  1150. {
  1151. ::FusionpLogError(
  1152. MSG_SXS_INVALID_FILE_HASH_FROM_COPY_CALLBACK,
  1153. CEventLogString(HashAlgNiceName));
  1154. goto Exit;
  1155. }
  1156. }
  1157. else
  1158. {
  1159. HashAlgId = FUSION_DEFAULT_HASH_ALGORITHM;
  1160. }
  1161. IFW32FALSE_EXIT(SourceBuffer.Win32AppendPathElement(SourceFileName, (SourceFileName != NULL) ? ::wcslen(SourceFileName) : 0));
  1162. IFW32FALSE_EXIT(::SxspGetFileSize(SXSP_GET_FILE_SIZE_FLAG_COMPRESSION_AWARE, SourceBuffer, SourceFileSize));
  1163. //
  1164. // And add the file's metadata to the currently running metadata blob
  1165. //
  1166. {
  1167. CSecurityMetaData *pMetaDataObject = reinterpret_cast<CSecurityMetaData*>(Data->Header.InstallationContext->SecurityMetaData);
  1168. if ( pMetaDataObject != NULL )
  1169. {
  1170. CSmallStringBuffer sbuffFileShortName;
  1171. IFW32FALSE_EXIT(sbuffFileShortName.Win32Assign(SourceFileName, ::wcslen(SourceFileName)));
  1172. IFW32FALSE_EXIT(pMetaDataObject->QuickAddFileHash(
  1173. sbuffFileShortName,
  1174. HashAlgId,
  1175. HashDataString));
  1176. }
  1177. }
  1178. if ((Data->Header.InstallationContext != NULL) &&
  1179. (Data->Header.InstallationContext->Callback != NULL))
  1180. {
  1181. Disposition = 0;
  1182. SXS_INSTALLATION_FILE_COPY_CALLBACK_PARAMETERS parameters = {sizeof(parameters)};
  1183. parameters.pvContext = Data->Header.InstallationContext->Context;
  1184. parameters.dwFileFlags = 0;
  1185. parameters.pAlternateSource = NULL; // future IStream
  1186. parameters.pSourceFile = SourceBuffer;
  1187. parameters.pDestinationFile = DestinationBuffer;
  1188. parameters.nFileSize = SourceFileSize;
  1189. parameters.nDisposition = 0;
  1190. IFW32FALSE_EXIT((*Data->Header.InstallationContext->Callback)(&parameters));
  1191. Disposition = parameters.nDisposition;
  1192. }
  1193. switch (Disposition)
  1194. {
  1195. default:
  1196. ::FusionpLogError(
  1197. MSG_SXS_INVALID_DISPOSITION_FROM_FILE_COPY_CALLBACK,
  1198. CEventLogString(SxspInstallDispositionToStringW(Disposition)));
  1199. goto Exit;
  1200. case SXS_INSTALLATION_FILE_COPY_DISPOSITION_FILE_COPIED:
  1201. {
  1202. if (fVerify)
  1203. {
  1204. ULONGLONG DestinationFileSize = 0;
  1205. IFW32FALSE_EXIT(::SxspGetFileSize(0, DestinationBuffer, DestinationFileSize));
  1206. INTERNAL_ERROR_CHECK(SourceFileSize == DestinationFileSize);
  1207. //
  1208. // (jonwis) Add a verification check to make sure that the file copied
  1209. // is really the one that they wanted from the file hash information.
  1210. // Do this only if we're not in OS-setup mode.
  1211. //
  1212. IFW32FALSE_EXIT(::SxspCheckHashDuringInstall(fHasHashData, DestinationBuffer, HashDataString, HashAlgId, HashCorrect));
  1213. if (HashCorrect != HashValidate_Matches)
  1214. {
  1215. ::FusionpDbgPrintEx(
  1216. FUSION_DBG_LEVEL_ERROR,
  1217. "SXS: %s : SxspCheckHashDuringInstall(file=%ls)\n",
  1218. __FUNCTION__,
  1219. static_cast<PCWSTR>(DestinationBuffer)
  1220. );
  1221. ORIGINATE_WIN32_FAILURE_AND_EXIT(FileHashMismatch, ERROR_SXS_FILE_HASH_MISMATCH);
  1222. }
  1223. }
  1224. }
  1225. break;
  1226. case SXS_INSTALLATION_FILE_COPY_DISPOSITION_FILE_QUEUED:
  1227. {
  1228. if (fVerify)
  1229. {
  1230. CFusionFilePathAndSize &verifyQueuedFileCopy = Locals->verifyQueuedFileCopy;
  1231. // Copy our hashing info over. Yes, I really do mean =, not ==.
  1232. if (verifyQueuedFileCopy.m_bHasHashInfo = fHasHashData)
  1233. {
  1234. IFW32FALSE_EXIT(verifyQueuedFileCopy.m_HashString.Win32Assign(HashDataString));
  1235. verifyQueuedFileCopy.m_HashAlgorithm = HashAlgId;
  1236. }
  1237. IFW32FALSE_EXIT(verifyQueuedFileCopy.m_path.Win32Assign(DestinationBuffer));
  1238. verifyQueuedFileCopy.m_size = SourceFileSize;
  1239. IFW32FALSE_EXIT(m_queuedFileCopies.Win32Append(verifyQueuedFileCopy));
  1240. }
  1241. }
  1242. break;
  1243. case SXS_INSTALLATION_FILE_COPY_DISPOSITION_PLEASE_MOVE:
  1244. case SXS_INSTALLATION_FILE_COPY_DISPOSITION_PLEASE_COPY:
  1245. {
  1246. CStringBuffer &DestinationDirectory = Locals->DestinationDirectory;
  1247. CMungeFileReadOnlynessAroundReplacement &MungeFileAttributes = Locals->MungeFileAttributes;
  1248. IFW32FALSE_EXIT(DestinationDirectory.Win32Assign(DestinationBuffer));
  1249. IFW32FALSE_EXIT(DestinationDirectory.Win32RemoveLastPathElement());
  1250. IFW32FALSE_EXIT(::FusionpCreateDirectories(DestinationDirectory, DestinationDirectory.Cch()));
  1251. if (Disposition == SXS_INSTALLATION_FILE_COPY_DISPOSITION_PLEASE_COPY)
  1252. {
  1253. DWORD dwLastError = 0;
  1254. IFW32FALSE_EXIT(MungeFileAttributes.Initialize(DestinationBuffer, fReplaceExisting));
  1255. fSuccess = ::SxspInstallDecompressOrCopyFileW(
  1256. SourceBuffer,
  1257. DestinationBuffer,
  1258. !fReplaceExisting); //bFailIfExist
  1259. dwLastError = ::FusionpGetLastWin32Error();
  1260. // If we failed because the file exists, that might be ok
  1261. if ((!fSuccess) && (dwLastError == ERROR_FILE_EXISTS))
  1262. {
  1263. ULONGLONG cbSource, cbDestination;
  1264. // If we got the file sizes, and they're equal, then we're reinstalling the
  1265. // same file again, which isn't technically an error. Some smarter work here,
  1266. // like comparing file hashes or PE headers, could be done.
  1267. if (::SxspGetFileSize(SXSP_GET_FILE_SIZE_FLAG_COMPRESSION_AWARE, SourceBuffer, cbSource) &&
  1268. ::SxspGetFileSize(0, DestinationBuffer, cbDestination) &&
  1269. (cbSource == cbDestination))
  1270. {
  1271. fSuccess = TRUE;
  1272. }
  1273. // Otherwise, we failed getting the sizes of those files, but we want to
  1274. // preserve the error from the original decompress-or-move call
  1275. else
  1276. {
  1277. ::FusionpSetLastWin32Error(dwLastError);
  1278. }
  1279. }
  1280. }
  1281. else
  1282. {
  1283. fSuccess = ::SxspInstallMoveFileExW(
  1284. SourceBuffer,
  1285. DestinationBuffer,
  1286. MOVEFILE_COPY_ALLOWED | (fReplaceExisting ? MOVEFILE_REPLACE_EXISTING : 0));
  1287. // move fails on from resource, so general idea: try copy upon move failure
  1288. if (!fSuccess)
  1289. {
  1290. DWORD dwLastError = ::FusionpGetLastWin32Error();
  1291. if ((dwLastError == ERROR_ACCESS_DENIED) ||
  1292. (dwLastError == ERROR_USER_MAPPED_FILE) ||
  1293. (dwLastError == ERROR_SHARING_VIOLATION))
  1294. {
  1295. fSuccess = ::SxspInstallDecompressOrCopyFileW(
  1296. SourceBuffer,
  1297. DestinationBuffer,
  1298. !fReplaceExisting); // bFailIfExist
  1299. }
  1300. }
  1301. }
  1302. if (fSuccess)
  1303. {
  1304. IFW32FALSE_EXIT(::SxspCheckHashDuringInstall(fHasHashData, DestinationBuffer, HashDataString, HashAlgId, HashCorrect));
  1305. if (HashCorrect != HashValidate_Matches)
  1306. {
  1307. ::FusionpDbgPrintEx(
  1308. FUSION_DBG_LEVEL_ERROR,
  1309. "SXS: %s : SxspCheckHashDuringInstall(file=%ls)\n",
  1310. __FUNCTION__,
  1311. static_cast<PCWSTR>(DestinationBuffer)
  1312. );
  1313. ORIGINATE_WIN32_FAILURE_AND_EXIT(FileHashMismatch, ERROR_SXS_FILE_HASH_MISMATCH);
  1314. }
  1315. else
  1316. fSuccess = TRUE;
  1317. goto Exit;
  1318. }
  1319. else
  1320. {
  1321. ULONGLONG iDupFileSize = 0;
  1322. DWORD dwLastError = ::FusionpGetLastWin32Error();
  1323. CStringBuffer &renameExistingAway = Locals->renameExistingAway;
  1324. CSmallStringBuffer &uidBuffer = Locals->uidBuffer;
  1325. CFullPathSplitPointers splitExisting;
  1326. bool fFatal =
  1327. (
  1328. dwLastError != ERROR_FILE_EXISTS // !fReplaceExisting
  1329. && dwLastError != ERROR_ALREADY_EXISTS // !fReplaceExisting
  1330. && dwLastError != ERROR_ACCESS_DENIED
  1331. && dwLastError != ERROR_USER_MAPPED_FILE // fReplaceExisting
  1332. && dwLastError != ERROR_SHARING_VIOLATION); // fReplaceExisting
  1333. if (fFatal)
  1334. {
  1335. ::SxspInstallPrint(
  1336. "SxsInstall: Copy/MoveFileW(%ls,%ls) failed %d, %s.\n",
  1337. static_cast<PCWSTR>(SourceBuffer),
  1338. static_cast<PCWSTR>(DestinationBuffer),
  1339. ::FusionpGetLastWin32Error(),
  1340. fFatal ? "fatal" : "not fatal");
  1341. ::FusionpDbgPrintEx(FUSION_DBG_LEVEL_ERROR,
  1342. "%s(%d): SXS.dll: Copy/MoveFileW(%ls,%ls) failed %d, %s.\n",
  1343. __FILE__,
  1344. __LINE__,
  1345. static_cast<PCWSTR>(SourceBuffer),
  1346. static_cast<PCWSTR>(DestinationBuffer),
  1347. ::FusionpGetLastWin32Error(),
  1348. fFatal ? "fatal" : "not fatal");
  1349. goto Exit;
  1350. }
  1351. //
  1352. // This could be winlogon (or setup) holding open comctl, so
  1353. // try harder. Move the file away and then copy.
  1354. // Consider ReplaceFile here for atomicity, but ReplaceFile
  1355. // is kind of big and scary and unknown.
  1356. //
  1357. if (fTransactional)
  1358. {
  1359. ::SxspInstallPrint("SxsInstall: Failure to copy file into temp, someone's opening temp?\n");
  1360. }
  1361. if (!splitExisting.Initialize(SourceBuffer))
  1362. {
  1363. goto CheckSizes;
  1364. }
  1365. if (!::SxspCreateWinSxsTempDirectory(renameExistingAway, NULL, &uidBuffer, NULL))
  1366. {
  1367. goto CheckSizes;
  1368. }
  1369. if (!renameExistingAway.Win32AppendPathElement(splitExisting.m_name, (splitExisting.m_name != NULL) ? ::wcslen(splitExisting.m_name) : 0))
  1370. {
  1371. goto CheckSizes;
  1372. }
  1373. //
  1374. // temporary file, no worry about compressed or not
  1375. //
  1376. if (!::MoveFileExW(DestinationBuffer, renameExistingAway, 0)) // no worry about compressed or not
  1377. {
  1378. ::SxspInstallPrint(
  1379. "SxsInstall: MoveFileExW(%ls,%ls,0) failed %d.\n",
  1380. static_cast<PCWSTR>(DestinationBuffer),
  1381. static_cast<PCWSTR>(renameExistingAway),
  1382. ::FusionpGetLastWin32Error());
  1383. goto CheckSizes;
  1384. }
  1385. if (!::SxspInstallDecompressOrCopyFileW(
  1386. SourceBuffer,
  1387. DestinationBuffer,
  1388. FALSE))
  1389. {
  1390. ::SxspInstallPrint(
  1391. "SxsInstall: CopyFile(%ls, %ls, TRUE) failed %d.\n",
  1392. static_cast<PCWSTR>(SourceBuffer),
  1393. static_cast<PCWSTR>(DestinationBuffer),
  1394. ::FusionpGetLastWin32Error());
  1395. // roll back
  1396. if (!::MoveFileExW(renameExistingAway, DestinationBuffer, 0)) // no worry about compressed or not
  1397. {
  1398. ::SxspInstallPrint(
  1399. "SxsInstall: Rollback MoveFileExW(%ls, %ls, 0) failed %d; this is very bad.\n",
  1400. static_cast<PCWSTR>(renameExistingAway),
  1401. static_cast<PCWSTR>(DestinationBuffer),
  1402. ::FusionpGetLastWin32Error()
  1403. );
  1404. }
  1405. goto CheckSizes;
  1406. }
  1407. fSuccess = TRUE;
  1408. goto Exit;
  1409. CheckSizes:
  1410. IFW32FALSE_EXIT(::SxspGetFileSize(0, DestinationBuffer, iDupFileSize));
  1411. if (iDupFileSize != SourceFileSize)
  1412. {
  1413. ::SxspInstallPrint("SxsInstall: " __FUNCTION__ " Error %d encountered, file sizes not the same, assumed equal, propagating error.\n", dwLastError);
  1414. ::FusionpSetLastWin32Error(dwLastError);
  1415. goto Exit;
  1416. }
  1417. ::SxspInstallPrint("SxsInstall: " __FUNCTION__ " Error %d encountered, file sizes the same, assumed equal, claiming success.\n", dwLastError);
  1418. }
  1419. break;
  1420. }
  1421. }
  1422. fSuccess = TRUE;
  1423. Exit:
  1424. return fSuccess;
  1425. }
  1426. VOID
  1427. CDllRedir::ContributorCallback(
  1428. PACTCTXCTB_CALLBACK_DATA Data
  1429. )
  1430. {
  1431. FN_TRACE();
  1432. CDllRedir *pDllRedir = reinterpret_cast<CDllRedir*>(Data->Header.ActCtxGenContext);
  1433. PSTRING_SECTION_GENERATION_CONTEXT SSGenContext = NULL;
  1434. PDLL_REDIRECTION_CONTEXT DllRedirectionContext = NULL;
  1435. PDLL_REDIRECTION_ENTRY Entry = NULL;
  1436. PDLL_REDIRECTION_ENTRY SystemDefaultEntry = NULL;
  1437. PDLL_REDIRECTION_ENTRY Syswow64DefaultEntry = NULL;
  1438. if (pDllRedir != NULL)
  1439. SSGenContext = pDllRedir->m_SSGenContext;
  1440. if (SSGenContext != NULL)
  1441. DllRedirectionContext = (PDLL_REDIRECTION_CONTEXT) ::SxsGetStringSectionGenerationContextCallbackContext(SSGenContext);
  1442. switch (Data->Header.Reason)
  1443. {
  1444. case ACTCTXCTB_CBREASON_PARSEENDING:
  1445. Data->ParseEnding.Success = FALSE;
  1446. /*
  1447. at this point we have enough information to form the install path,
  1448. so get the TeeStream to start writing the manifest to disk
  1449. */
  1450. if (Data->Header.ManifestOperation == MANIFEST_OPERATION_INSTALL)
  1451. IFW32FALSE_EXIT(InstallManifest(Data->Header.ManifestOperationFlags, Data->ParseEnding.AssemblyContext));
  1452. Data->ParseEnding.Success = TRUE;
  1453. break;
  1454. case ACTCTXCTB_CBREASON_PARSEENDED:
  1455. if ( Data->Header.ManifestOperation == MANIFEST_OPERATION_INSTALL )
  1456. {
  1457. PACTCTXCTB_CBPARSEENDED pParseEnded = reinterpret_cast<PACTCTXCTB_CBPARSEENDED>(Data);
  1458. CSecurityMetaData *psmdSecurity =
  1459. reinterpret_cast<CSecurityMetaData*>(pParseEnded->AssemblyContext->SecurityMetaData);
  1460. CTeeStreamWithHash *pTeeStreamWithHash =
  1461. reinterpret_cast<CTeeStreamWithHash*>(pParseEnded->AssemblyContext->TeeStreamForManifestInstall);
  1462. CFusionArray<BYTE> baManifestHashBytes;
  1463. if ( ( psmdSecurity != NULL ) && ( pTeeStreamWithHash != NULL ) )
  1464. {
  1465. IFW32FALSE_EXIT(baManifestHashBytes.Win32Initialize());
  1466. IFW32FALSE_EXIT(pTeeStreamWithHash->GetCryptHash().Win32GetValue(baManifestHashBytes));
  1467. IFW32FALSE_EXIT(psmdSecurity->SetManifestHash( baManifestHashBytes ));
  1468. }
  1469. }
  1470. break;
  1471. case ACTCTXCTB_CBREASON_ACTCTXGENBEGINNING:
  1472. Data->GenBeginning.Success = FALSE;
  1473. if (Data->Header.ManifestOperation == MANIFEST_OPERATION_GENERATE_ACTIVATION_CONTEXT)
  1474. {
  1475. IFALLOCFAILED_EXIT(DllRedirectionContext = new DLL_REDIRECTION_CONTEXT);
  1476. IFW32FALSE_EXIT(::SxsInitStringSectionGenerationContext(
  1477. &m_SSGenContext,
  1478. ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION_FORMAT_WHISTLER,
  1479. TRUE,
  1480. &::SxspDllRedirectionStringSectionGenerationCallback,
  1481. DllRedirectionContext));
  1482. DllRedirectionContext = NULL;
  1483. }
  1484. if (Data->Header.ManifestOperation == MANIFEST_OPERATION_INSTALL)
  1485. {
  1486. IFW32FALSE_EXIT(this->BeginInstall(Data));
  1487. }
  1488. Data->GenBeginning.Success = TRUE;
  1489. break;
  1490. case ACTCTXCTB_CBREASON_ACTCTXGENENDING:
  1491. Data->GenEnding.Success = FALSE;
  1492. if (Data->Header.ManifestOperation == MANIFEST_OPERATION_INSTALL)
  1493. IFW32FALSE_EXIT(this->EndInstall(Data));
  1494. Data->GenEnding.Success = TRUE;
  1495. break;
  1496. case ACTCTXCTB_CBREASON_ACTCTXGENENDED:
  1497. if (m_SSGenContext != NULL)
  1498. ::SxsDestroyStringSectionGenerationContext(m_SSGenContext);
  1499. if (DllRedirectionContext != NULL)
  1500. FUSION_DELETE_SINGLETON(DllRedirectionContext);
  1501. m_SSGenContext = NULL;
  1502. break;
  1503. case ACTCTXCTB_CBREASON_ALLPARSINGDONE:
  1504. Data->AllParsingDone.Success = FALSE;
  1505. if (SSGenContext != NULL)
  1506. IFW32FALSE_EXIT(::SxsDoneModifyingStringSectionGenerationContext(SSGenContext));
  1507. Data->AllParsingDone.Success = TRUE;
  1508. break;
  1509. case ACTCTXCTB_CBREASON_GETSECTIONSIZE:
  1510. Data->GetSectionSize.Success = FALSE;
  1511. INTERNAL_ERROR_CHECK(SSGenContext);
  1512. IFW32FALSE_EXIT(::SxsGetStringSectionGenerationContextSectionSize(SSGenContext, &Data->GetSectionSize.SectionSize));
  1513. Data->GetSectionSize.Success = TRUE;
  1514. break;
  1515. case ACTCTXCTB_CBREASON_ELEMENTPARSED:
  1516. {
  1517. Data->ElementParsed.Success = FALSE;
  1518. ULONG MappedValue = 0;
  1519. bool fFound = false;
  1520. enum MappedValues
  1521. {
  1522. eAssembly,
  1523. eAssemblyFile,
  1524. };
  1525. static const ELEMENT_PATH_MAP_ENTRY s_rgEntries[] =
  1526. {
  1527. { 1, L"urn:schemas-microsoft-com:asm.v1^assembly", NUMBER_OF(L"urn:schemas-microsoft-com:asm.v1^assembly") - 1, eAssembly },
  1528. { 2, L"urn:schemas-microsoft-com:asm.v1^assembly!urn:schemas-microsoft-com:asm.v1^file", NUMBER_OF(L"urn:schemas-microsoft-com:asm.v1^assembly!urn:schemas-microsoft-com:asm.v1^file") - 1, eAssemblyFile },
  1529. };
  1530. IFW32FALSE_EXIT(
  1531. ::SxspProcessElementPathMap(
  1532. Data->ElementParsed.ParseContext,
  1533. s_rgEntries,
  1534. NUMBER_OF(s_rgEntries),
  1535. MappedValue,
  1536. fFound));
  1537. if (fFound)
  1538. {
  1539. switch (MappedValue)
  1540. {
  1541. default:
  1542. INTERNAL_ERROR_CHECK2(
  1543. FALSE,
  1544. "Invalid mapped value returned from SxspProcessElementPathMap()");
  1545. case eAssembly:
  1546. break;
  1547. case eAssemblyFile:
  1548. {
  1549. CSmallStringBuffer &FileNameBuffer = this->ContributorCallbackLocals.FileNameBuffer;
  1550. CSmallStringBuffer &LoadFromBuffer = this->ContributorCallbackLocals.LoadFromBuffer;
  1551. CSmallStringBuffer &HashValueBuffer = this->ContributorCallbackLocals.HashValueBuffer;
  1552. SIZE_T cb = 0;
  1553. bool rfFileNameValid = false;
  1554. // We look for required attributes etc first so that if we're only parsing, it's
  1555. // common code.
  1556. IFW32FALSE_EXIT(
  1557. ::SxspGetAttributeValue(
  1558. SXSP_GET_ATTRIBUTE_VALUE_FLAG_REQUIRED_ATTRIBUTE,
  1559. &s_AttributeName_name,
  1560. &Data->ElementParsed,
  1561. fFound,
  1562. sizeof(FileNameBuffer),
  1563. &FileNameBuffer,
  1564. cb,
  1565. NULL,
  1566. 0));
  1567. INTERNAL_ERROR_CHECK(fFound);
  1568. IFW32FALSE_EXIT(::SxspIsFileNameValidForManifest(FileNameBuffer, rfFileNameValid));
  1569. if (!rfFileNameValid)
  1570. {
  1571. (*Data->ElementParsed.ParseContext->ErrorCallbacks.InvalidAttributeValue)(
  1572. Data->ElementParsed.ParseContext,
  1573. &s_AttributeName_name);
  1574. ::FusionpSetLastWin32Error(ERROR_SXS_MANIFEST_PARSE_ERROR);
  1575. goto Exit;
  1576. }
  1577. //
  1578. // Ensure that the hash string is valid
  1579. //
  1580. IFW32FALSE_EXIT(
  1581. ::SxspGetAttributeValue(
  1582. 0,
  1583. &s_AttributeName_hash,
  1584. &Data->ElementParsed,
  1585. fFound,
  1586. sizeof(HashValueBuffer),
  1587. &HashValueBuffer,
  1588. cb,
  1589. NULL,
  1590. 0));
  1591. //
  1592. // Odd numbers of characters in the hash string will be bad later.
  1593. //
  1594. if (fFound && (HashValueBuffer.Cch() % 2))
  1595. {
  1596. (*Data->ElementParsed.ParseContext->ErrorCallbacks.InvalidAttributeValue)(
  1597. Data->ElementParsed.ParseContext,
  1598. &s_AttributeName_hash);
  1599. ::FusionpSetLastWin32Error(ERROR_SXS_MANIFEST_PARSE_ERROR);
  1600. goto Exit;
  1601. }
  1602. //
  1603. // And that the hash-alg string is valid too
  1604. //
  1605. IFW32FALSE_EXIT(
  1606. ::SxspGetAttributeValue(
  1607. 0,
  1608. &s_AttributeName_hashalg,
  1609. &Data->ElementParsed,
  1610. fFound,
  1611. sizeof(HashValueBuffer),
  1612. &HashValueBuffer,
  1613. cb,
  1614. NULL,
  1615. 0));
  1616. if (fFound)
  1617. {
  1618. ALG_ID aid;
  1619. if (!::SxspHashAlgFromString(HashValueBuffer, aid))
  1620. {
  1621. (*Data->ElementParsed.ParseContext->ErrorCallbacks.InvalidAttributeValue)(
  1622. Data->ElementParsed.ParseContext,
  1623. &s_AttributeName_hashalg);
  1624. ::FusionpSetLastWin32Error(ERROR_SXS_MANIFEST_PARSE_ERROR);
  1625. goto Exit;
  1626. }
  1627. }
  1628. IFW32FALSE_EXIT(
  1629. ::SxspGetAttributeValue(
  1630. 0,
  1631. &s_AttributeName_loadFrom,
  1632. &Data->ElementParsed,
  1633. fFound,
  1634. sizeof(LoadFromBuffer),
  1635. &LoadFromBuffer,
  1636. cb,
  1637. NULL,
  1638. 0));
  1639. if (fFound)
  1640. {
  1641. // We're not allowed to install assemblies that have a loadFrom= and the only
  1642. // manifests with them that we can activate are ones that don't live in the assembly store.
  1643. if ((Data->Header.ManifestOperation == MANIFEST_OPERATION_INSTALL) ||
  1644. ((Data->ElementParsed.AssemblyContext->Flags & ACTCTXCTB_ASSEMBLY_CONTEXT_IS_ROOT_ASSEMBLY) == 0))
  1645. {
  1646. // You can't install an assembly with a loadfrom=foo file; it's only provided for
  1647. // app compat...
  1648. (*Data->ElementParsed.ParseContext->ErrorCallbacks.AttributeNotAllowed)(
  1649. Data->ElementParsed.ParseContext,
  1650. &s_AttributeName_loadFrom);
  1651. ::FusionpSetLastWin32Error(ERROR_SXS_MANIFEST_PARSE_ERROR);
  1652. goto Exit;
  1653. }
  1654. }
  1655. //
  1656. // Always update the file count.
  1657. //
  1658. ASSERT(Data->Header.ActCtxGenContext != NULL);
  1659. if (Data->Header.ActCtxGenContext)
  1660. {
  1661. Data->Header.pOriginalActCtxGenCtx->m_ulFileCount++;
  1662. }
  1663. // If we're installing, call back to the copy function
  1664. if (Data->Header.ManifestOperation == MANIFEST_OPERATION_INSTALL)
  1665. IFW32FALSE_EXIT(this->InstallFile(Data, FileNameBuffer));
  1666. // If we are generating an activation context, add it to the context.
  1667. if (Data->Header.ManifestOperation == MANIFEST_OPERATION_GENERATE_ACTIVATION_CONTEXT)
  1668. {
  1669. IFALLOCFAILED_EXIT(Entry = new DLL_REDIRECTION_ENTRY);
  1670. IFW32FALSE_EXIT(Entry->FileNameBuffer.Win32Assign(FileNameBuffer, FileNameBuffer.Cch()));
  1671. if (LoadFromBuffer.Cch() != 0)
  1672. {
  1673. Entry->AssemblyPathBuffer.Win32Assign(LoadFromBuffer, LoadFromBuffer.Cch());
  1674. Entry->AssemblyPathIsLoadFrom = true;
  1675. // If the value does not end in a slash, we assume it directly refers to
  1676. // a file.
  1677. if (!LoadFromBuffer.HasTrailingPathSeparator())
  1678. Entry->PathIncludesBaseName = true;
  1679. }
  1680. // for system default, we have a duplicate entry if this dll also exists under %windir%\system32.
  1681. if (Data->Header.Flags & SXS_GENERATE_ACTCTX_SYSTEM_DEFAULT)
  1682. {
  1683. CSmallStringBuffer &DllUnderSystem32 = this->ContributorCallbackLocals.DllUnderSystem32;
  1684. CStringBufferAccessor sba;
  1685. sba.Attach(&DllUnderSystem32);
  1686. DWORD dwNecessary =::ExpandEnvironmentStringsW(
  1687. L"%windir%\\system32\\",
  1688. sba.GetBufferPtr(),
  1689. sba.GetBufferCchAsDWORD() - 1);
  1690. if ((dwNecessary == 0 ) || (dwNecessary >= (sba.GetBufferCch() - 1)))
  1691. {
  1692. // error case : it is weird for 64 bytes buffer is too small for system directory
  1693. ::FusionpDbgPrintEx(
  1694. FUSION_DBG_LEVEL_ERROR,
  1695. "SXS.DLL: %s: ExpandEnvironmentStringsW() for %windir%\\system32 failed with lastError=%d\n",
  1696. __FUNCTION__,
  1697. static_cast<PCWSTR>(DllUnderSystem32),
  1698. ::GetLastError()
  1699. );
  1700. goto Exit;
  1701. }
  1702. sba.Detach();
  1703. IFW32FALSE_EXIT(DllUnderSystem32.Win32Append(FileNameBuffer, FileNameBuffer.Cch()));
  1704. bool fExist = false;
  1705. //
  1706. // create another new entry and insert it into the section
  1707. //
  1708. IFALLOCFAILED_EXIT(SystemDefaultEntry = new DLL_REDIRECTION_ENTRY);
  1709. IFW32FALSE_EXIT(SystemDefaultEntry->FileNameBuffer.Win32Assign(DllUnderSystem32, DllUnderSystem32.Cch()));
  1710. // copy from Entry except FileNameBuffer
  1711. SystemDefaultEntry->AssemblyPathBuffer.Win32Assign(Entry->AssemblyPathBuffer, Entry->AssemblyPathBuffer.Cch());
  1712. SystemDefaultEntry->AssemblyPathIsLoadFrom = Entry->AssemblyPathIsLoadFrom;
  1713. SystemDefaultEntry->PathIncludesBaseName = Entry->PathIncludesBaseName;
  1714. SystemDefaultEntry->SystemDefaultRedirectedSystem32Dll = true;
  1715. #ifdef _WIN64
  1716. // check whether it is a wow64
  1717. const WCHAR *Value = NULL;
  1718. SIZE_T Cch = 0;
  1719. bool rfWow64 = false;
  1720. IFW32FALSE_EXIT(::SxspGetAssemblyIdentityAttributeValue(
  1721. SXSP_GET_ASSEMBLY_IDENTITY_ATTRIBUTE_VALUE_FLAG_NOT_FOUND_RETURNS_NULL,
  1722. Data->ElementParsed.AssemblyContext->AssemblyIdentity,
  1723. &s_IdentityAttribute_processorArchitecture, &Value, &Cch));
  1724. if (Cch == 5)
  1725. {
  1726. INTERNAL_ERROR_CHECK(Value != NULL);
  1727. if (((Value[0] == L'w') || (Value[0] == L'W')) &&
  1728. ((Value[1] == L'o') || (Value[1] == L'O')) &&
  1729. ((Value[2] == L'w') || (Value[2] == L'W')) &&
  1730. (Value[3] == L'6') &&
  1731. (Value[4] == L'4'))
  1732. rfWow64 = true;
  1733. }
  1734. if (!rfWow64)
  1735. {
  1736. if (Cch == 3)
  1737. {
  1738. INTERNAL_ERROR_CHECK(Value != NULL);
  1739. if (((Value[0] == L'X') || (Value[0] == L'x')) &&
  1740. (Value[1] == L'8') &&
  1741. (Value[2] == L'6'))
  1742. rfWow64 = true;
  1743. }
  1744. }
  1745. if (rfWow64)
  1746. {
  1747. CSmallStringBuffer &DllUnderSyswow64 = this->ContributorCallbackLocals.DllUnderSyswow64;
  1748. CStringBufferAccessor sba2;
  1749. sba2.Attach(&DllUnderSyswow64);
  1750. DWORD dwSyswow64 = ::GetSystemWow64DirectoryW(sba2.GetBufferPtr(), sba2.GetBufferCchAsDWORD() - 1);
  1751. if ((dwSyswow64 == 0 ) || (dwSyswow64 >= (sba2.GetBufferCch() - 1)))
  1752. {
  1753. // error case : it is weird for 64 bytes buffer is too small for system directory
  1754. ::FusionpDbgPrintEx(
  1755. FUSION_DBG_LEVEL_ERROR,
  1756. "SXS.DLL: %s: get %windir%\\syswow64 failed with lastError=%d\n",
  1757. __FUNCTION__,
  1758. static_cast<PCWSTR>(DllUnderSyswow64),
  1759. ::GetLastError()
  1760. );
  1761. goto Exit;
  1762. }
  1763. sba2.Detach();
  1764. IFW32FALSE_EXIT(DllUnderSyswow64.Win32EnsureTrailingPathSeparator()); // for syswow64
  1765. IFW32FALSE_EXIT(DllUnderSyswow64.Win32Append(FileNameBuffer, FileNameBuffer.Cch()));
  1766. IFALLOCFAILED_EXIT(Syswow64DefaultEntry = new DLL_REDIRECTION_ENTRY);
  1767. IFW32FALSE_EXIT(Syswow64DefaultEntry->FileNameBuffer.Win32Assign(DllUnderSyswow64, DllUnderSyswow64.Cch()));
  1768. // copy from Entry except FileNameBuffer
  1769. Syswow64DefaultEntry->AssemblyPathBuffer.Win32Assign(Entry->AssemblyPathBuffer, Entry->AssemblyPathBuffer.Cch());
  1770. Syswow64DefaultEntry->AssemblyPathIsLoadFrom = Entry->AssemblyPathIsLoadFrom;
  1771. Syswow64DefaultEntry->PathIncludesBaseName = Entry->PathIncludesBaseName;
  1772. Syswow64DefaultEntry->SystemDefaultRedirectedSystem32Dll = true;
  1773. }
  1774. #endif
  1775. }
  1776. if (Entry)
  1777. {
  1778. if (!::SxsAddStringToStringSectionGenerationContext(
  1779. (PSTRING_SECTION_GENERATION_CONTEXT) m_SSGenContext,
  1780. Entry->FileNameBuffer,
  1781. Entry->FileNameBuffer.Cch(),
  1782. Entry,
  1783. Data->ElementParsed.AssemblyContext->AssemblyRosterIndex,
  1784. ERROR_SXS_DUPLICATE_DLL_NAME))
  1785. {
  1786. ::FusionpLogError(
  1787. MSG_SXS_DLLREDIR_CONTRIB_ADD_FILE_MAP_ENTRY,
  1788. CUnicodeString(Entry->FileNameBuffer, Entry->FileNameBuffer.Cch()),
  1789. CEventLogLastError());
  1790. goto Exit;
  1791. }
  1792. Entry = NULL;
  1793. }
  1794. if(SystemDefaultEntry)
  1795. {
  1796. if (!::SxsAddStringToStringSectionGenerationContext(
  1797. (PSTRING_SECTION_GENERATION_CONTEXT) m_SSGenContext,
  1798. SystemDefaultEntry->FileNameBuffer,
  1799. SystemDefaultEntry->FileNameBuffer.Cch(),
  1800. SystemDefaultEntry,
  1801. Data->ElementParsed.AssemblyContext->AssemblyRosterIndex,
  1802. ERROR_SXS_DUPLICATE_DLL_NAME))
  1803. {
  1804. ::FusionpLogError(
  1805. MSG_SXS_DLLREDIR_CONTRIB_ADD_FILE_MAP_ENTRY,
  1806. CUnicodeString(SystemDefaultEntry->FileNameBuffer, SystemDefaultEntry->FileNameBuffer.Cch()),
  1807. CEventLogLastError());
  1808. goto Exit;
  1809. }
  1810. SystemDefaultEntry = NULL;
  1811. }
  1812. #ifdef _WIN64
  1813. if (Syswow64DefaultEntry)
  1814. {
  1815. if (!::SxsAddStringToStringSectionGenerationContext(
  1816. (PSTRING_SECTION_GENERATION_CONTEXT) m_SSGenContext,
  1817. Syswow64DefaultEntry->FileNameBuffer,
  1818. Syswow64DefaultEntry->FileNameBuffer.Cch(),
  1819. Syswow64DefaultEntry,
  1820. Data->ElementParsed.AssemblyContext->AssemblyRosterIndex,
  1821. ERROR_SXS_DUPLICATE_DLL_NAME))
  1822. {
  1823. ::FusionpLogError(
  1824. MSG_SXS_DLLREDIR_CONTRIB_ADD_FILE_MAP_ENTRY,
  1825. CUnicodeString(Syswow64DefaultEntry->FileNameBuffer, Syswow64DefaultEntry->FileNameBuffer.Cch()),
  1826. CEventLogLastError());
  1827. goto Exit;
  1828. }
  1829. Syswow64DefaultEntry = NULL;
  1830. }
  1831. #endif
  1832. }
  1833. }
  1834. break;
  1835. }
  1836. }
  1837. }
  1838. // Everything's groovy!
  1839. Data->ElementParsed.Success = TRUE;
  1840. break;
  1841. case ACTCTXCTB_CBREASON_GETSECTIONDATA:
  1842. Data->GetSectionData.Success = FALSE;
  1843. IFW32FALSE_EXIT(::SxsGetStringSectionGenerationContextSectionData(
  1844. m_SSGenContext,
  1845. Data->GetSectionData.SectionSize,
  1846. Data->GetSectionData.SectionDataStart,
  1847. NULL));
  1848. Data->GetSectionData.Success = TRUE;
  1849. break;
  1850. }
  1851. Exit:
  1852. FUSION_DELETE_SINGLETON(Entry);
  1853. FUSION_DELETE_SINGLETON(SystemDefaultEntry);
  1854. FUSION_DELETE_SINGLETON(Syswow64DefaultEntry);
  1855. }
  1856. BOOL
  1857. SxspDllRedirectionStringSectionGenerationCallback(
  1858. PVOID Context,
  1859. ULONG Reason,
  1860. PVOID CallbackData
  1861. )
  1862. {
  1863. BOOL fSuccess = FALSE;
  1864. switch (Reason)
  1865. {
  1866. default:
  1867. goto Exit;
  1868. case STRING_SECTION_GENERATION_CONTEXT_CALLBACK_REASON_GETUSERDATASIZE:
  1869. case STRING_SECTION_GENERATION_CONTEXT_CALLBACK_REASON_GETUSERDATA:
  1870. // will use the user data area later to store common paths
  1871. break;
  1872. case STRING_SECTION_GENERATION_CONTEXT_CALLBACK_REASON_ENTRYDELETED:
  1873. {
  1874. PSTRING_SECTION_GENERATION_CONTEXT_CBDATA_ENTRYDELETED CBData =
  1875. (PSTRING_SECTION_GENERATION_CONTEXT_CBDATA_ENTRYDELETED) CallbackData;
  1876. PDLL_REDIRECTION_ENTRY Entry = (PDLL_REDIRECTION_ENTRY) CBData->DataContext;
  1877. FUSION_DELETE_SINGLETON(Entry);
  1878. break;
  1879. }
  1880. case STRING_SECTION_GENERATION_CONTEXT_CALLBACK_REASON_GETDATASIZE:
  1881. {
  1882. PSTRING_SECTION_GENERATION_CONTEXT_CBDATA_GETDATASIZE CBData =
  1883. (PSTRING_SECTION_GENERATION_CONTEXT_CBDATA_GETDATASIZE) CallbackData;
  1884. PDLL_REDIRECTION_ENTRY Entry = (PDLL_REDIRECTION_ENTRY) CBData->DataContext;
  1885. CBData->DataSize = sizeof(ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION);
  1886. if (Entry->AssemblyPathBuffer.Cch() != 0)
  1887. {
  1888. CBData->DataSize += sizeof(ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION_PATH_SEGMENT);
  1889. CBData->DataSize += (Entry->AssemblyPathBuffer.Cch() * sizeof(WCHAR));
  1890. }
  1891. break;
  1892. }
  1893. case STRING_SECTION_GENERATION_CONTEXT_CALLBACK_REASON_GETDATA:
  1894. {
  1895. PSTRING_SECTION_GENERATION_CONTEXT_CBDATA_GETDATA CBData =
  1896. (PSTRING_SECTION_GENERATION_CONTEXT_CBDATA_GETDATA) CallbackData;
  1897. PDLL_REDIRECTION_ENTRY Entry = (PDLL_REDIRECTION_ENTRY) CBData->DataContext;
  1898. PACTIVATION_CONTEXT_DATA_DLL_REDIRECTION Info;
  1899. SIZE_T BytesLeft = CBData->BufferSize;
  1900. SIZE_T BytesWritten = 0;
  1901. PVOID Cursor;
  1902. Info = (PACTIVATION_CONTEXT_DATA_DLL_REDIRECTION) CBData->Buffer;
  1903. Cursor = (PVOID) (Info + 1);
  1904. if (BytesLeft < sizeof(ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION))
  1905. {
  1906. ::FusionpSetLastWin32Error(ERROR_INSUFFICIENT_BUFFER);
  1907. goto Exit;
  1908. }
  1909. BytesWritten += sizeof(ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION);
  1910. BytesLeft -= sizeof(ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION);
  1911. Info->Size = sizeof(ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION);
  1912. Info->Flags = 0;
  1913. Info->TotalPathLength = static_cast<ULONG>(Entry->AssemblyPathBuffer.Cch() * sizeof(WCHAR));
  1914. if (Entry->PathIncludesBaseName)
  1915. Info->Flags |= ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION_PATH_INCLUDES_BASE_NAME;
  1916. if (Entry->SystemDefaultRedirectedSystem32Dll)
  1917. Info->Flags |= ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION_PATH_SYSTEM_DEFAULT_REDIRECTED_SYSTEM32_DLL;
  1918. if (Entry->AssemblyPathBuffer.Cch() == 0)
  1919. {
  1920. // If there's no path, there's no segments!
  1921. Info->PathSegmentCount = 0;
  1922. Info->PathSegmentOffset = 0;
  1923. Info->Flags |= ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION_PATH_OMITS_ASSEMBLY_ROOT;
  1924. }
  1925. else
  1926. {
  1927. PACTIVATION_CONTEXT_DATA_DLL_REDIRECTION_PATH_SEGMENT Segment;
  1928. Info->PathSegmentCount = 1;
  1929. Info->PathSegmentOffset = static_cast<LONG>(((LONG_PTR) Cursor) - ((LONG_PTR) CBData->SectionHeader));
  1930. // If this is a loadfrom="foo" file and the string contains a %, set the expand flag...
  1931. if ((Entry->AssemblyPathIsLoadFrom) && (Entry->AssemblyPathBuffer.ContainsCharacter(L'%')))
  1932. Info->Flags |= ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION_PATH_EXPAND;
  1933. Segment = (PACTIVATION_CONTEXT_DATA_DLL_REDIRECTION_PATH_SEGMENT) Cursor;
  1934. Cursor = (PVOID) (Segment + 1);
  1935. if (BytesLeft < sizeof(ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION_PATH_SEGMENT))
  1936. {
  1937. ::FusionpSetLastWin32Error(ERROR_INSUFFICIENT_BUFFER);
  1938. goto Exit;
  1939. }
  1940. BytesWritten += sizeof(ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION_PATH_SEGMENT);
  1941. BytesLeft -= sizeof(ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION_PATH_SEGMENT);
  1942. Segment->Length = Info->TotalPathLength;
  1943. Segment->Offset = static_cast<LONG>(((LONG_PTR) Cursor) - ((LONG_PTR) CBData->SectionHeader));
  1944. if (BytesLeft < (Entry->AssemblyPathBuffer.Cch() * sizeof(WCHAR)))
  1945. {
  1946. ::FusionpSetLastWin32Error(ERROR_INSUFFICIENT_BUFFER);
  1947. goto Exit;
  1948. }
  1949. BytesWritten += (Entry->AssemblyPathBuffer.Cch() * sizeof(WCHAR));
  1950. BytesLeft -= (Entry->AssemblyPathBuffer.Cch() * sizeof(WCHAR));
  1951. memcpy(Cursor, static_cast<PCWSTR>(Entry->AssemblyPathBuffer), Entry->AssemblyPathBuffer.Cch() * sizeof(WCHAR));
  1952. }
  1953. CBData->BytesWritten = BytesWritten;
  1954. }
  1955. }
  1956. fSuccess = TRUE;
  1957. Exit:
  1958. return fSuccess;
  1959. }