aboutsummaryrefslogtreecommitdiff
path: root/src/burn/engine/bundlepackageengine.cpp
diff options
context:
space:
mode:
authorSean Hall <r.sean.hall@gmail.com>2022-06-14 15:10:07 -0500
committerSean Hall <r.sean.hall@gmail.com>2022-06-14 21:51:14 -0500
commit98c369a92891244bde76448ae4a2b623b3ab394c (patch)
tree398105d02a888ba41b426e84965375e491d79bb7 /src/burn/engine/bundlepackageengine.cpp
parentdea657295df261bb0e3e4d620eeae321531e3a11 (diff)
downloadwix-98c369a92891244bde76448ae4a2b623b3ab394c.tar.gz
wix-98c369a92891244bde76448ae4a2b623b3ab394c.tar.bz2
wix-98c369a92891244bde76448ae4a2b623b3ab394c.zip
Allow BundlePackage to fallback to QuietUninstallString to uninstall.
Partial implementation of 6756
Diffstat (limited to 'src/burn/engine/bundlepackageengine.cpp')
-rw-r--r--src/burn/engine/bundlepackageengine.cpp123
1 files changed, 119 insertions, 4 deletions
diff --git a/src/burn/engine/bundlepackageengine.cpp b/src/burn/engine/bundlepackageengine.cpp
index 81279cf6..7ae12a1e 100644
--- a/src/burn/engine/bundlepackageengine.cpp
+++ b/src/burn/engine/bundlepackageengine.cpp
@@ -18,6 +18,7 @@ static HRESULT ExecuteBundle(
18 __in BURN_CACHE* pCache, 18 __in BURN_CACHE* pCache,
19 __in BURN_VARIABLES* pVariables, 19 __in BURN_VARIABLES* pVariables,
20 __in BOOL fRollback, 20 __in BOOL fRollback,
21 __in BOOL fCacheAvailable,
21 __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler, 22 __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler,
22 __in LPVOID pvContext, 23 __in LPVOID pvContext,
23 __in BOOTSTRAPPER_ACTION_STATE action, 24 __in BOOTSTRAPPER_ACTION_STATE action,
@@ -30,6 +31,11 @@ static HRESULT ExecuteBundle(
30 __in_z_opt LPCWSTR wzEngineWorkingDirectory, 31 __in_z_opt LPCWSTR wzEngineWorkingDirectory,
31 __out BOOTSTRAPPER_APPLY_RESTART* pRestart 32 __out BOOTSTRAPPER_APPLY_RESTART* pRestart
32 ); 33 );
34static HRESULT DetectArpEntry(
35 __in BURN_PACKAGE* pPackage,
36 __out BOOL* pfRegistered,
37 __out LPWSTR* psczQuietUninstallString
38 );
33static BOOTSTRAPPER_RELATION_TYPE ConvertRelationType( 39static BOOTSTRAPPER_RELATION_TYPE ConvertRelationType(
34 __in BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE relationType 40 __in BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE relationType
35 ); 41 );
@@ -197,6 +203,7 @@ extern "C" void BundlePackageEnginePackageUninitialize(
197 ) 203 )
198{ 204{
199 ReleaseStr(pPackage->Bundle.sczBundleId); 205 ReleaseStr(pPackage->Bundle.sczBundleId);
206 ReleaseStr(pPackage->Bundle.sczArpKeyPath);
200 ReleaseVerutilVersion(pPackage->Bundle.pVersion); 207 ReleaseVerutilVersion(pPackage->Bundle.pVersion);
201 ReleaseStr(pPackage->Bundle.sczRegistrationKey); 208 ReleaseStr(pPackage->Bundle.sczRegistrationKey);
202 ReleaseStr(pPackage->Bundle.sczInstallArguments); 209 ReleaseStr(pPackage->Bundle.sczInstallArguments);
@@ -600,6 +607,7 @@ extern "C" HRESULT BundlePackageEngineExecutePackage(
600 __in BURN_CACHE* pCache, 607 __in BURN_CACHE* pCache,
601 __in BURN_VARIABLES* pVariables, 608 __in BURN_VARIABLES* pVariables,
602 __in BOOL fRollback, 609 __in BOOL fRollback,
610 __in BOOL fCacheAvailable,
603 __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler, 611 __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler,
604 __in LPVOID pvContext, 612 __in LPVOID pvContext,
605 __out BOOTSTRAPPER_APPLY_RESTART* pRestart 613 __out BOOTSTRAPPER_APPLY_RESTART* pRestart
@@ -613,7 +621,7 @@ extern "C" HRESULT BundlePackageEngineExecutePackage(
613 BOOTSTRAPPER_RELATION_TYPE relationType = BOOTSTRAPPER_RELATION_CHAIN_PACKAGE; 621 BOOTSTRAPPER_RELATION_TYPE relationType = BOOTSTRAPPER_RELATION_CHAIN_PACKAGE;
614 BURN_PACKAGE* pPackage = pExecuteAction->bundlePackage.pPackage; 622 BURN_PACKAGE* pPackage = pExecuteAction->bundlePackage.pPackage;
615 623
616 return ExecuteBundle(pCache, pVariables, fRollback, pfnGenericMessageHandler, pvContext, action, relationType, pPackage, FALSE, wzParent, wzIgnoreDependencies, wzAncestors, wzEngineWorkingDirectory, pRestart); 624 return ExecuteBundle(pCache, pVariables, fRollback, fCacheAvailable, pfnGenericMessageHandler, pvContext, action, relationType, pPackage, FALSE, wzParent, wzIgnoreDependencies, wzAncestors, wzEngineWorkingDirectory, pRestart);
617} 625}
618 626
619extern "C" HRESULT BundlePackageEngineExecuteRelatedBundle( 627extern "C" HRESULT BundlePackageEngineExecuteRelatedBundle(
@@ -635,7 +643,7 @@ extern "C" HRESULT BundlePackageEngineExecuteRelatedBundle(
635 BOOTSTRAPPER_RELATION_TYPE relationType = ConvertRelationType(pRelatedBundle->planRelationType); 643 BOOTSTRAPPER_RELATION_TYPE relationType = ConvertRelationType(pRelatedBundle->planRelationType);
636 BURN_PACKAGE* pPackage = &pRelatedBundle->package; 644 BURN_PACKAGE* pPackage = &pRelatedBundle->package;
637 645
638 return ExecuteBundle(pCache, pVariables, fRollback, pfnGenericMessageHandler, pvContext, action, relationType, pPackage, TRUE, wzParent, wzIgnoreDependencies, wzAncestors, wzEngineWorkingDirectory, pRestart); 646 return ExecuteBundle(pCache, pVariables, fRollback, TRUE, pfnGenericMessageHandler, pvContext, action, relationType, pPackage, TRUE, wzParent, wzIgnoreDependencies, wzAncestors, wzEngineWorkingDirectory, pRestart);
639} 647}
640 648
641extern "C" void BundlePackageEngineUpdateInstallRegistrationState( 649extern "C" void BundlePackageEngineUpdateInstallRegistrationState(
@@ -678,10 +686,10 @@ static BUNDLE_QUERY_CALLBACK_RESULT CALLBACK QueryRelatedBundlesCallback(
678 BOOTSTRAPPER_RELATION_TYPE relationType = RelatedBundleConvertRelationType(pBundle->relationType); 686 BOOTSTRAPPER_RELATION_TYPE relationType = RelatedBundleConvertRelationType(pBundle->relationType);
679 BOOL fPerMachine = BUNDLE_INSTALL_CONTEXT_MACHINE == pBundle->installContext; 687 BOOL fPerMachine = BUNDLE_INSTALL_CONTEXT_MACHINE == pBundle->installContext;
680 688
681 if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pBundle->wzBundleId, -1, pPackage->Bundle.sczBundleId, -1)) 689 if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pBundle->wzBundleId, -1, pPackage->Bundle.sczBundleId, -1) &&
690 pPackage->Bundle.fWin64 == (REG_KEY_64BIT == pBundle->regBitness))
682 { 691 {
683 Assert(BOOTSTRAPPER_RELATION_UPGRADE == relationType); 692 Assert(BOOTSTRAPPER_RELATION_UPGRADE == relationType);
684 Assert(pPackage->Bundle.fWin64 == (REG_KEY_64BIT == pBundle->regBitness));
685 693
686 pContext->fSelfFound = TRUE; 694 pContext->fSelfFound = TRUE;
687 } 695 }
@@ -727,6 +735,7 @@ static HRESULT ExecuteBundle(
727 __in BURN_CACHE* pCache, 735 __in BURN_CACHE* pCache,
728 __in BURN_VARIABLES* pVariables, 736 __in BURN_VARIABLES* pVariables,
729 __in BOOL fRollback, 737 __in BOOL fRollback,
738 __in BOOL fCacheAvailable,
730 __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler, 739 __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler,
731 __in LPVOID pvContext, 740 __in LPVOID pvContext,
732 __in BOOTSTRAPPER_ACTION_STATE action, 741 __in BOOTSTRAPPER_ACTION_STATE action,
@@ -749,6 +758,10 @@ static HRESULT ExecuteBundle(
749 LPWSTR sczUserArgs = NULL; 758 LPWSTR sczUserArgs = NULL;
750 LPWSTR sczUserArgsObfuscated = NULL; 759 LPWSTR sczUserArgsObfuscated = NULL;
751 LPWSTR sczCommandObfuscated = NULL; 760 LPWSTR sczCommandObfuscated = NULL;
761 LPWSTR sczArpUninstallString = NULL;
762 int argcArp = 0;
763 LPWSTR* argvArp = NULL;
764 BOOL fRegistered = FALSE;
752 HANDLE hExecutableFile = INVALID_HANDLE_VALUE; 765 HANDLE hExecutableFile = INVALID_HANDLE_VALUE;
753 STARTUPINFOW si = { }; 766 STARTUPINFOW si = { };
754 PROCESS_INFORMATION pi = { }; 767 PROCESS_INFORMATION pi = { };
@@ -772,6 +785,51 @@ static HRESULT ExecuteBundle(
772 hr = PathGetDirectory(sczExecutablePath, &sczCachedDirectory); 785 hr = PathGetDirectory(sczExecutablePath, &sczCachedDirectory);
773 ExitOnFailure(hr, "Failed to get cached path for related bundle: %ls", pPackage->sczId); 786 ExitOnFailure(hr, "Failed to get cached path for related bundle: %ls", pPackage->sczId);
774 } 787 }
788 else if (!fCacheAvailable)
789 {
790 ExitOnNull(BOOTSTRAPPER_ACTION_STATE_UNINSTALL == action, hr, E_INVALIDARG, "The only supported action when the cache is not available is UNINSTALL.");
791
792 hr = DetectArpEntry(pPackage, &fRegistered, &sczArpUninstallString);
793 ExitOnFailure(hr, "Failed to query ARP for uninstall.");
794
795 if (!fRegistered)
796 {
797 if (fRollback)
798 {
799 LogId(REPORT_STANDARD, MSG_ROLLBACK_PACKAGE_SKIPPED, pPackage->sczId, LoggingActionStateToString(action), LoggingPackageStateToString(BOOTSTRAPPER_PACKAGE_STATE_ABSENT));
800 }
801 else
802 {
803 LogId(REPORT_STANDARD, MSG_ATTEMPTED_UNINSTALL_ABSENT_PACKAGE, pPackage->sczId);
804 }
805
806 ExitFunction();
807 }
808
809 ExitOnNull(sczArpUninstallString, hr, E_INVALIDARG, "QuietUninstallString is null.");
810
811 hr = AppParseCommandLine(sczArpUninstallString, &argcArp, &argvArp);
812 ExitOnFailure(hr, "Failed to parse QuietUninstallString: %ls.", sczArpUninstallString);
813
814 ExitOnNull(argcArp, hr, E_INVALIDARG, "QuietUninstallString must contain an executable path.");
815
816 hr = StrAllocString(&sczExecutablePath, argvArp[0], 0);
817 ExitOnFailure(hr, "Failed to copy executable path.");
818
819 if (pPackage->fPerMachine)
820 {
821 hr = ApprovedExesVerifySecureLocation(pCache, pVariables, sczExecutablePath);
822 ExitOnFailure(hr, "Failed to verify the QuietUninstallString executable path is in a secure location: %ls", sczExecutablePath);
823 if (S_FALSE == hr)
824 {
825 LogStringLine(REPORT_STANDARD, "The QuietUninstallString executable path is not in a secure location: %ls", sczExecutablePath);
826 ExitFunction1(hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED));
827 }
828 }
829
830 hr = PathGetDirectory(sczExecutablePath, &sczCachedDirectory);
831 ExitOnFailure(hr, "Failed to get parent directory for QuietUninstallString executable path: %ls", sczExecutablePath);
832 }
775 else 833 else
776 { 834 {
777 // get cached executable path 835 // get cached executable path
@@ -859,6 +917,12 @@ static HRESULT ExecuteBundle(
859 hr = StrAllocFormatted(&sczBaseCommand, L"\"%ls\"", sczExecutablePath); 917 hr = StrAllocFormatted(&sczBaseCommand, L"\"%ls\"", sczExecutablePath);
860 ExitOnFailure(hr, "Failed to allocate base command."); 918 ExitOnFailure(hr, "Failed to allocate base command.");
861 919
920 for (int i = 1; i < argcArp; ++i)
921 {
922 hr = AppAppendCommandLineArgument(&sczBaseCommand, argvArp[i]);
923 ExitOnFailure(hr, "Failed to append argument from ARP.");
924 }
925
862 if (!fRunEmbedded) 926 if (!fRunEmbedded)
863 { 927 {
864 hr = StrAllocConcat(&sczBaseCommand, L" -quiet", 0); 928 hr = StrAllocConcat(&sczBaseCommand, L" -quiet", 0);
@@ -962,6 +1026,12 @@ LExit:
962 StrSecureZeroFreeString(sczUserArgs); 1026 StrSecureZeroFreeString(sczUserArgs);
963 ReleaseStr(sczUserArgsObfuscated); 1027 ReleaseStr(sczUserArgsObfuscated);
964 ReleaseStr(sczCommandObfuscated); 1028 ReleaseStr(sczCommandObfuscated);
1029 ReleaseStr(sczArpUninstallString);
1030
1031 if (argvArp)
1032 {
1033 AppFreeCommandLineArgs(argvArp);
1034 }
965 1035
966 ReleaseHandle(pi.hThread); 1036 ReleaseHandle(pi.hThread);
967 ReleaseHandle(pi.hProcess); 1037 ReleaseHandle(pi.hProcess);
@@ -974,6 +1044,51 @@ LExit:
974 return hr; 1044 return hr;
975} 1045}
976 1046
1047static HRESULT DetectArpEntry(
1048 __in BURN_PACKAGE* pPackage,
1049 __out BOOL* pfRegistered,
1050 __out LPWSTR* psczQuietUninstallString
1051 )
1052{
1053 HRESULT hr = S_OK;
1054 HKEY hKey = NULL;
1055 HKEY hkRoot = pPackage->fPerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
1056 REG_KEY_BITNESS keyBitness = pPackage->Bundle.fWin64 ? REG_KEY_64BIT : REG_KEY_32BIT;
1057
1058 *pfRegistered = FALSE;
1059 if (psczQuietUninstallString)
1060 {
1061 ReleaseNullStr(*psczQuietUninstallString);
1062 }
1063
1064 if (!pPackage->Bundle.sczArpKeyPath)
1065 {
1066 hr = PathConcatRelativeToBase(L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\", pPackage->Bundle.sczBundleId, &pPackage->Bundle.sczArpKeyPath);
1067 ExitOnFailure(hr, "Failed to build full key path.");
1068 }
1069
1070 hr = RegOpenEx(hkRoot, pPackage->Bundle.sczArpKeyPath, KEY_READ, keyBitness, &hKey);
1071 if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr || HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
1072 {
1073 ExitFunction1(hr = S_OK);
1074 }
1075 ExitOnFailure(hr, "Failed to open registry key: %ls.", pPackage->Bundle.sczArpKeyPath);
1076
1077 *pfRegistered = TRUE;
1078
1079 hr = RegReadString(hKey, L"QuietUninstallString", psczQuietUninstallString);
1080 if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
1081 {
1082 hr = S_OK;
1083 }
1084 ExitOnFailure(hr, "Failed to read QuietUninstallString.");
1085
1086LExit:
1087 ReleaseRegKey(hKey);
1088
1089 return hr;
1090}
1091
977static BOOTSTRAPPER_RELATION_TYPE ConvertRelationType( 1092static BOOTSTRAPPER_RELATION_TYPE ConvertRelationType(
978 __in BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE relationType 1093 __in BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE relationType
979 ) 1094 )