/*++ Copyright (c) Microsoft Corporation Module Name: sxssfc_repairshortnames.cpp Abstract: after textmode setup extracts asms*.cab and write hivesxs.inf, write the correct shortnames into the registry Author: Jay Krell (Jaykrell) June 2002 Revision History: --*/ #include "stdinc.h" #include "recover.h" #include "cassemblyrecoveryinfo.h" #include "sxssfcscan.h" BOOL SxspSetupGetSourceInfo( HINF InfHandle, // handle to the INF file UINT SourceId, // ID of the source media UINT InfoDesired, // information to retrieve CBaseStringBuffer &buff, LPDWORD RequiredSize // optional, buffer size needed ) { FN_PROLOG_WIN32 CStringBufferAccessor acc; DWORD RequiredSize2 = 0; BOOL fTooSmall = FALSE; if (RequiredSize == NULL) { RequiredSize = &RequiredSize2; } acc.Attach(&buff); IFW32FALSE_EXIT_UNLESS2( ::SetupGetSourceInfoW( InfHandle, SourceId, InfoDesired, acc, acc.GetBufferCchAsDWORD(), RequiredSize ), LIST_1(ERROR_INSUFFICIENT_BUFFER), fTooSmall); if (fTooSmall) { acc.Detach(); IFW32FALSE_EXIT(buff.Win32ResizeBuffer(*RequiredSize + 1, eDoNotPreserveBufferContents)); acc.Attach(&buff); IFW32FALSE_EXIT( ::SetupGetSourceInfoW( InfHandle, SourceId, InfoDesired, acc, acc.GetBufferCchAsDWORD(), RequiredSize )); } FN_EPILOG } BOOL SxspGetWindowsSetupPrompt( CBaseStringBuffer &rbuffWinsxsRoot ) // // This code is based closely on code in base\ntsetup\syssetup\copy.c // Legacy wfp is a little different, it opens layout.inf, but the results // should be the same. // { FN_PROLOG_WIN32 CFusionSetupInfFile InfFile; CStringBuffer InfPath; const static UNICODE_STRING inf = RTL_CONSTANT_STRING(L"inf"); const static UNICODE_STRING filename_inf = RTL_CONSTANT_STRING(L"layout.inf"); UINT SourceId = 0; const PCWSTR SystemRoot = USER_SHARED_DATA->NtSystemRoot; IFW32FALSE_EXIT(InfPath.Win32Assign(SystemRoot, ::wcslen(SystemRoot))); IFW32FALSE_EXIT(InfPath.Win32AppendPathElement(&inf)); IFW32FALSE_EXIT(InfPath.Win32AppendPathElement(&filename_inf)); IFW32FALSE_EXIT(InfFile.Win32SetupOpenInfFileW(InfPath, NULL, INF_STYLE_WIN4, NULL)); IFW32FALSE_EXIT(::SetupGetSourceFileLocationW(InfFile, NULL, L"shell32.dll", &SourceId, NULL, 0, NULL)); IFW32FALSE_EXIT(::SxspSetupGetSourceInfo(InfFile, SourceId, SRCINFO_DESCRIPTION, rbuffWinsxsRoot, NULL)); FN_EPILOG } BOOL SxspModifyRegistryData( DWORD Flags ) { // // In postbuild we run sxsofflineinstall. // This includes creating hivesxs.inf to populate the registry // with data needed for windows file protection. // // The data includes short names, but we don't know the short names // until textmode setup. The code in textmode setup is fairly generic // and just expands .cabs. // // We do not need the short names to be correct until we expect // bogus file changes against short file names to induce recovery // of assemblies. It is reasonable to assume that these won't happen // until setup is done and the system is running. // // Therefore it is sufficient to fixup the shortnames after textmode setup, // such as in a RunOnce entry. // /* Here is an example of what we are fixing up. [AddReg] HKLM,"\Software\Microsoft\Windows\CurrentVersion\SideBySide\Installations HKLM,"\...\IA64_Microsoft.Windows.Common-Controls_6595b64144ccf1df_5.82.0.0_x-ww_B9C4A0A5","Identity",0x00001000,"Microsoft.Windows.Common-Controls,processorArchitecture="IA64",publicKeyToken="6595b64144ccf1df",type="win32",version="5.82.0.0"" HKLM,"\...\IA64_Microsoft.Windows.Common-Controls_6595b64144ccf1df_5.82.0.0_x-ww_B9C4A0A5","Catalog",0x00011001,0x00000001 HKLM,"\...\IA64_Microsoft.Windows.Common-Controls_6595b64144ccf1df_5.82.0.0_x-ww_B9C4A0A5","ManifestSHA1Hash",0x00001001,3b,26,4a,90,08,0f,6a,dd,b6,00,55,5b,a5,a4,9e,21,ad,e3,90,84 HKLM,"\...\IA64_Microsoft.Windows.Common-Controls_6595b64144ccf1df_5.82.0.0_x-ww_B9C4A0A5","ShortName",0x00001000,"IA64_M~2.0_X" HKLM,"\...\IA64_Microsoft.Windows.Common-Controls_6595b64144ccf1df_5.82.0.0_x-ww_B9C4A0A5","ShortCatalogName",0x00001000,"IA64_M~4.CAT" HKLM,"\...\IA64_Microsoft.Windows.Common-Controls_6595b64144ccf1df_5.82.0.0_x-ww_B9C4A0A5","ShortManifestName",0x00001000,"IA64_M~4.MAN" HKLM,"\...\IA64_Microsoft.Windows.Common-Controls_6595b64144ccf1df_5.82.0.0_x-ww_B9C4A0A5","PublicKeyToken",0x00001001,65,95,b6,41,44,cc,f1,df HKLM,"\...\IA64_Microsoft.Windows.Common-Controls_6595b64144ccf1df_5.82.0.0_x-ww_B9C4A0A5","Codebase",0x00001000,"x-ms-windows-source:W_fusi_bin.IA64chk/asms/58200/Msft/Windows/Common/Controls/Controls.man" HKLM,"\...\IA64_Microsoft.Windows.Common-Controls_6595b64144ccf1df_5.82.0.0_x-ww_B9C4A0A5\Codebases\OS","Prompt",0x00001000,"(textmode setup placeholder)" HKLM,"\...\IA64_Microsoft.Windows.Common-Controls_6595b64144ccf1df_5.82.0.0_x-ww_B9C4A0A5\Codebases\OS","URL",0x00001000,"x-ms-windows-source:W_fusi_bin.IA64chk/asms/58200/Msft/Windows/Common/Controls/Controls.man" HKLM,"\...\IA64_Microsoft.Windows.Common-Controls_6595b64144ccf1df_5.82.0.0_x-ww_B9C4A0A5\Files\0","",0x00001000,"comctl32.dll" HKLM,"\...\IA64_Microsoft.Windows.Common-Controls_6595b64144ccf1df_5.82.0.0_x-ww_B9C4A0A5\Files\0","SHA1",0x00001001,76,c3,6e,4c,c4,10,14,7f,38,c8,bc,cd,4b,4f,b2,90,d8,0a,7c,d7 HKLM,"\...\IA64_Microsoft.Windows.Common-Controls_6595b64144ccf1df_5.82.0.0_x-ww_B9C4A0A5\References","OS",0x00001000,"Foom" IA64_Microsoft.Windows.Common-Controls_6595b64144ccf1df_5.82.0.0_x-ww_B9C4A0A5 */ BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess); CFusionRegKey regkeyInstallations; CFusionRegKey regkeyInstallation; DWORD dwRegSubKeyIndex = 0; BOOL fNoMoreItems = FALSE; FILETIME LastWriteFileTimeIgnored = { 0 }; CTinyStringBuffer buffInstallationName; CTinyStringBuffer buffWinsxsRoot; CTinyStringBuffer *buffLongFullPath = NULL; CTinyStringBuffer buffShortFullPath; CTinyStringBuffer buffShortPathLastElement; CTinyStringBuffer buffTextualIdentity; CTinyStringBuffer buffEmpty; CTinyStringBuffer buffWindowsSetupPrompt; CTinyStringBuffer buffCurrentPromptInRegistry; CTinyStringBuffer buffFullPathToManifest; CTinyStringBuffer buffFullPathToCatalog; CTinyStringBuffer buffFullPathToPayloadDirectory; SIZE_T i = 0; const bool fRepairAll = ((Flags & SXSP_MODIFY_REGISTRY_DATA_FLAG_REPAIR_ALL) != 0); const bool fRepairShort = fRepairAll || ((Flags & SXSP_MODIFY_REGISTRY_DATA_FLAG_REPAIR_SHORT_NAMES) != 0); const bool fDeleteShort = ((Flags & SXSP_MODIFY_REGISTRY_DATA_FLAG_DELETE_SHORT_NAMES) != 0); const bool fRepairPrompt = fRepairAll || ((Flags & SXSP_MODIFY_REGISTRY_DATA_FLAG_REPAIR_OFFLINE_INSTALL_REFRESH_PROMPTS) != 0); const bool fValidate = ((Flags & SXSP_MODIFY_REGISTRY_DATA_VALIDATE) != 0); #if DBG bool fDbgPrintBecauseHashValidationFailed = false; #endif PARAMETER_CHECK(Flags != 0); PARAMETER_CHECK((Flags & ~SXSP_MODIFY_REGISTRY_DATA_FLAG_VALID_FLAGS) == 0); IFW32FALSE_EXIT(::SxspGetAssemblyRootDirectory(buffWinsxsRoot)); IFW32FALSE_EXIT(::SxspOpenAssemblyInstallationKey(0, KEY_READ | KEY_SET_VALUE | FUSIONP_KEY_WOW64_64KEY, regkeyInstallations)); if (fRepairPrompt) { IFW32FALSE_EXIT(::SxspGetWindowsSetupPrompt(buffWindowsSetupPrompt)); } for ((dwRegSubKeyIndex = 0), (fNoMoreItems = FALSE); !fNoMoreItems ; ++dwRegSubKeyIndex) { bool fNotFound = false; CSmartAssemblyIdentity AssemblyIdentity; PROBING_ATTRIBUTE_CACHE AttributeCache = { 0 }; CFusionRegKey codebase_os; IFW32FALSE_EXIT( regkeyInstallations.EnumKey( dwRegSubKeyIndex, buffInstallationName, &LastWriteFileTimeIgnored, &fNoMoreItems)); if (fNoMoreItems) { break; } IFW32FALSE_EXIT( regkeyInstallations.OpenSubKey( regkeyInstallation, buffInstallationName, KEY_READ | KEY_SET_VALUE | ((fRepairPrompt || fValidate) ? KEY_ENUMERATE_SUB_KEYS : 0) )); IFW32FALSE_EXIT( regkeyInstallation.GetValue( CSMD_TOPLEVEL_IDENTITY, buffTextualIdentity )); IFW32FALSE_EXIT(::SxspCreateAssemblyIdentityFromTextualString(buffTextualIdentity, &AssemblyIdentity)); typedef struct _SXSP_GENERATE_PATH_FUNCTION_REGISTRY_VALUE_NAME { BOOL (*GeneratePathFunction)( IN const CBaseStringBuffer &AssemblyRootDirectory, IN PCASSEMBLY_IDENTITY pAssemblyIdentity, IN OUT PPROBING_ATTRIBUTE_CACHE ppac, IN OUT CBaseStringBuffer &PathBuffer ); PCWSTR RegistryValueName; } SXSP_GENERATE_PATH_FUNCTION_REGISTRY_VALUE_NAME, *PSXSP_GENERATE_PATH_FUNCTION_REGISTRY_VALUE_NAME; typedef const SXSP_GENERATE_PATH_FUNCTION_REGISTRY_VALUE_NAME *PCSXSP_GENERATE_PATH_FUNCTION_REGISTRY_VALUE_NAME; const static SXSP_GENERATE_PATH_FUNCTION_REGISTRY_VALUE_NAME s_rgFunctionRegistryValueName[] = { // // Note that policies are not currently wfp protected, // but it's easy and obvious to put reasonable data // in the registry for them. // { &::SxspGenerateSxsPath_FullPathToManifestOrPolicyFile, CSMD_TOPLEVEL_SHORTMANIFEST }, { &::SxspGenerateSxsPath_FullPathToCatalogFile, CSMD_TOPLEVEL_SHORTCATALOG }, { &::SxspGenerateSxsPath_FullPathToPayloadOrPolicyDirectory, CSMD_TOPLEVEL_SHORTNAME } }; CBaseStringBuffer * const rgpbuffFullPaths[] = { &buffFullPathToManifest, &buffFullPathToCatalog, &buffFullPathToPayloadDirectory }; // // first generate all three fullpaths // for (i = 0 ; i != NUMBER_OF(s_rgFunctionRegistryValueName) ; ++i) { const PCSXSP_GENERATE_PATH_FUNCTION_REGISTRY_VALUE_NAME p = &s_rgFunctionRegistryValueName[i]; CBaseStringBuffer * const pbuffLongFullPath = rgpbuffFullPaths[i]; IFW32FALSE_EXIT((*p->GeneratePathFunction)( buffWinsxsRoot, AssemblyIdentity, &AttributeCache, *pbuffLongFullPath)); IFW32FALSE_EXIT(pbuffLongFullPath->Win32RemoveTrailingPathSeparators()); } // // optionally repair short names // if (fRepairShort) { for (i = 0 ; i != NUMBER_OF(s_rgFunctionRegistryValueName) ; ++i) { const PCSXSP_GENERATE_PATH_FUNCTION_REGISTRY_VALUE_NAME p = &s_rgFunctionRegistryValueName[i]; CBaseStringBuffer * const pbuffLongFullPath = rgpbuffFullPaths[i]; { DWORD dwWin32Error = NO_ERROR; IFW32FALSE_EXIT( ::SxspGetShortPathName( *pbuffLongFullPath, buffShortFullPath, dwWin32Error, static_cast(4), ERROR_PATH_NOT_FOUND, ERROR_FILE_NOT_FOUND, ERROR_BAD_NET_NAME, ERROR_BAD_NETPATH)); if (dwWin32Error == NO_ERROR) { IFW32FALSE_EXIT(buffShortFullPath.Win32GetLastPathElement(buffShortPathLastElement)); IFW32FALSE_EXIT(regkeyInstallation.SetValue(p->RegistryValueName, buffShortPathLastElement)); } } } } // // optionally delete short names // if (fDeleteShort) { for (i = 0 ; i != NUMBER_OF(s_rgFunctionRegistryValueName) ; ++i) { IFW32FALSE_EXIT(regkeyInstallation.DeleteValue(s_rgFunctionRegistryValueName[i].RegistryValueName)); } } // // validate hashes and repair prompts // BE SURE TO validate hashes first, as we filter what assemblies // to repair based on the placeholder prompt // IFW32FALSE_EXIT_UNLESS2( regkeyInstallation.OpenSubKey( codebase_os, CSMD_TOPLEVEL_CODEBASES L"\\" SXS_INSTALL_REFERENCE_SCHEME_OSINSTALL_STRING, KEY_READ | KEY_SET_VALUE), LIST_2(ERROR_PATH_NOT_FOUND, ERROR_FILE_NOT_FOUND), fNotFound); // // OpenSubKey actually eats some errors, so you can't trust // fNotFound or the BOOL returned. // if (!fNotFound && codebase_os.IsValid()) { fNotFound = false; IFW32FALSE_EXIT_UNLESS2( codebase_os.GetValue( CSMD_CODEBASES_PROMPTSTRING, buffCurrentPromptInRegistry), LIST_2(ERROR_PATH_NOT_FOUND, ERROR_FILE_NOT_FOUND), fNotFound); if (!fNotFound) { if (::FusionpEqualStringsI( buffCurrentPromptInRegistry, SXSP_OFFLINE_INSTALL_REFRESH_PROMPT_PLACEHOLDER, NUMBER_OF(SXSP_OFFLINE_INSTALL_REFRESH_PROMPT_PLACEHOLDER) - 1)) { if (fValidate) { CAssemblyRecoveryInfo AssemblyRecoveryInfo; bool fNoAssembly = false; DWORD dwResult = 0; IFW32FALSE_EXIT(AssemblyRecoveryInfo.Initialize()); IFW32FALSE_EXIT(AssemblyRecoveryInfo.AssociateWithAssembly(buffInstallationName, fNoAssembly)); IFW32FALSE_EXIT(::SxspValidateEntireAssembly( SXS_VALIDATE_ASM_FLAG_CHECK_EVERYTHING, AssemblyRecoveryInfo, dwResult, AssemblyIdentity )); if (dwResult != SXS_VALIDATE_ASM_FLAG_VALID_PERFECT) { ::FusionpDbgPrintEx( FUSION_DBG_LEVEL_SETUPLOG, "The assembly %ls contains file hash errors.\n", static_cast(buffTextualIdentity)); ::FusionpDbgPrintEx( FUSION_DBG_LEVEL_ERROR, "SXS.DLL %s: The assembly %ls contains file hash errors.\n", __FUNCTION__, static_cast(buffTextualIdentity)); ::FusionpSetLastWin32Error(ERROR_SXS_FILE_HASH_MISMATCH); #if DBG fDbgPrintBecauseHashValidationFailed = true; #endif goto Exit; } } if (fRepairPrompt) { IFW32FALSE_EXIT( codebase_os.SetValue( CSMD_CODEBASES_PROMPTSTRING, buffWindowsSetupPrompt)); } } } } } fSuccess = TRUE; Exit: if ((!fSuccess && ::FusionpDbgWouldPrintAtFilterLevel(FUSION_DBG_LEVEL_ERROR)) #if DBG || fDbgPrintBecauseHashValidationFailed #endif ) { // // multiple dbgprints due to 511 limit // use tick count to link together seperate prints // CSxsPreserveLastError ple; DWORD TickCount = ::GetTickCount(); ::FusionpDbgPrintEx( FUSION_DBG_LEVEL_ERROR, "SXS.DLL: %s 0x%lx error 0x%lx\n", __FUNCTION__, TickCount, ple.LastError()); ::FusionpDbgPrintEx( FUSION_DBG_LEVEL_ERROR, "SXS.DLL: %s 0x%lx dwRegSubKeyIndex 0x%lx\n", __FUNCTION__, TickCount, dwRegSubKeyIndex); ::FusionpDbgPrintEx( FUSION_DBG_LEVEL_ERROR, "SXS.DLL: %s 0x%lx i 0x%Ix\n", __FUNCTION__, TickCount, i); ::FusionpDbgPrintEx( FUSION_DBG_LEVEL_ERROR, "SXS.DLL: %s 0x%lx buffInstallationName %ls\n", __FUNCTION__, TickCount, static_cast(buffInstallationName)); ::FusionpDbgPrintEx( FUSION_DBG_LEVEL_ERROR, "SXS.DLL: %s 0x%lx buffTextualIdentity %ls\n", __FUNCTION__, TickCount, static_cast(buffTextualIdentity)); ::FusionpDbgPrintEx( FUSION_DBG_LEVEL_ERROR, "SXS.DLL: %s 0x%lx buffFullPathToManifest %ls\n", __FUNCTION__, TickCount, static_cast(buffFullPathToManifest)); ::FusionpDbgPrintEx( FUSION_DBG_LEVEL_ERROR, "SXS.DLL: %s 0x%lx buffFullPathToCatalog %ls\n", __FUNCTION__, TickCount, static_cast(buffFullPathToCatalog)); ::FusionpDbgPrintEx( FUSION_DBG_LEVEL_ERROR, "SXS.DLL: %s 0x%lx buffFullPathToPayloadDirectory %ls\n", __FUNCTION__, TickCount, static_cast(buffFullPathToPayloadDirectory)); ::FusionpDbgPrintEx( FUSION_DBG_LEVEL_ERROR, "SXS.DLL: %s 0x%lx buffShortFullPath %ls\n", __FUNCTION__, TickCount, static_cast(buffShortFullPath)); ::FusionpDbgPrintEx( FUSION_DBG_LEVEL_ERROR, "SXS.DLL: %s 0x%lx buffShortPathLastElement %ls\n", __FUNCTION__, TickCount, static_cast(buffShortPathLastElement)); ple.Restore(); } return fSuccess; } BOOL SxspDeleteShortNamesInRegistry( VOID ) { return ::SxspModifyRegistryData(SXSP_MODIFY_REGISTRY_DATA_FLAG_DELETE_SHORT_NAMES); } STDAPI DllInstall( BOOL fInstall, PCWSTR pszCmdLine ) { FN_PROLOG_HR // // Just ignore uninstall requests. // if (!fInstall) { FN_SUCCESSFUL_EXIT(); } // // It doesn't look like guimode setup ever passes in // anything for pszCmdLine, so we don't look at it. // IFW32FALSE_EXIT(::SxspModifyRegistryData(SXSP_MODIFY_REGISTRY_DATA_FLAG_REPAIR_ALL | SXSP_MODIFY_REGISTRY_DATA_VALIDATE)); FN_EPILOG }