From eee408f4f52823038ca6da83693efd135c8511c8 Mon Sep 17 00:00:00 2001
From: Sean Hall <r.sean.hall@gmail.com>
Date: Sun, 16 Jan 2022 14:08:45 -0600
Subject: Make Burn require a non-empty KB for MsuPackages to be uninstallable.

---
 src/burn/engine/msuengine.cpp | 21 ++++++++++++++-------
 src/burn/engine/package.cpp   |  6 +++++-
 src/burn/engine/package.h     |  1 +
 3 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/src/burn/engine/msuengine.cpp b/src/burn/engine/msuengine.cpp
index 4db425be..44386a6d 100644
--- a/src/burn/engine/msuengine.cpp
+++ b/src/burn/engine/msuengine.cpp
@@ -39,6 +39,17 @@ extern "C" HRESULT MsuEngineParsePackageFromXml(
     hr = XmlGetAttributeEx(pixnMsuPackage, L"DetectCondition", &pPackage->Msu.sczDetectCondition);
     ExitOnFailure(hr, "Failed to get @DetectCondition.");
 
+    // We can only uninstall MSU packages if they have a KB and we are on Win7 or newer.
+    if (pPackage->Msu.sczKB && *pPackage->Msu.sczKB && ::IsWindows7OrGreater())
+    {
+        pPackage->Msu.fUninstallable = TRUE;
+    }
+    else
+    {
+        pPackage->fPermanent = TRUE;
+        pPackage->Msu.fUninstallable = FALSE;
+    }
+
 LExit:
     return hr;
 }
@@ -92,10 +103,6 @@ extern "C" HRESULT MsuEnginePlanCalculatePackage(
     HRESULT hr = S_OK;
     BOOTSTRAPPER_ACTION_STATE execute = BOOTSTRAPPER_ACTION_STATE_NONE;
     BOOTSTRAPPER_ACTION_STATE rollback = BOOTSTRAPPER_ACTION_STATE_NONE;
-    BOOL fAllowUninstall = FALSE;
-
-    // We can only uninstall MSU packages if they have a KB and we are on Win7 or newer.
-    fAllowUninstall = pPackage->Msu.sczKB && *pPackage->Msu.sczKB && ::IsWindows7OrGreater();
 
     // execute action
     switch (pPackage->currentState)
@@ -110,11 +117,11 @@ extern "C" HRESULT MsuEnginePlanCalculatePackage(
 
         case BOOTSTRAPPER_REQUEST_STATE_ABSENT: __fallthrough;
         case BOOTSTRAPPER_REQUEST_STATE_CACHE:
-            execute = fAllowUninstall && !pPackage->fPermanent ? BOOTSTRAPPER_ACTION_STATE_UNINSTALL : BOOTSTRAPPER_ACTION_STATE_NONE;
+            execute = !pPackage->fPermanent ? BOOTSTRAPPER_ACTION_STATE_UNINSTALL : BOOTSTRAPPER_ACTION_STATE_NONE;
             break;
 
         case BOOTSTRAPPER_REQUEST_STATE_FORCE_ABSENT:
-            execute = fAllowUninstall ? BOOTSTRAPPER_ACTION_STATE_UNINSTALL : BOOTSTRAPPER_ACTION_STATE_NONE;
+            execute = pPackage->Msu.fUninstallable ? BOOTSTRAPPER_ACTION_STATE_UNINSTALL : BOOTSTRAPPER_ACTION_STATE_NONE;
             break;
 
         default:
@@ -166,7 +173,7 @@ extern "C" HRESULT MsuEnginePlanCalculatePackage(
             {
             case BOOTSTRAPPER_REQUEST_STATE_PRESENT: __fallthrough;
             case BOOTSTRAPPER_REQUEST_STATE_REPAIR:
-                rollback = fAllowUninstall ? BOOTSTRAPPER_ACTION_STATE_UNINSTALL : BOOTSTRAPPER_ACTION_STATE_NONE;
+                rollback = !pPackage->fPermanent ? BOOTSTRAPPER_ACTION_STATE_UNINSTALL : BOOTSTRAPPER_ACTION_STATE_NONE;
                 break;
 
             default:
diff --git a/src/burn/engine/package.cpp b/src/burn/engine/package.cpp
index 72da817f..8a80194e 100644
--- a/src/burn/engine/package.cpp
+++ b/src/burn/engine/package.cpp
@@ -161,7 +161,6 @@ extern "C" HRESULT PackagesParseFromXml(
         // @Permanent
         hr = XmlGetYesNoAttribute(pixnNode, L"Permanent", &pPackage->fPermanent);
         ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Permanent.");
-        pPackage->fCanAffectRegistration = !pPackage->fPermanent;
 
         // @Vital
         hr = XmlGetYesNoAttribute(pixnNode, L"Vital", &pPackage->fVital);
@@ -244,6 +243,9 @@ extern "C" HRESULT PackagesParseFromXml(
             case BURN_PACKAGE_TYPE_EXE:
                 fUninstallable = pPackage->Exe.fUninstallable;
                 break;
+            case BURN_PACKAGE_TYPE_MSU:
+                fUninstallable = pPackage->Msu.fUninstallable;
+                break;
             }
 
             if (!fUninstallable)
@@ -252,6 +254,8 @@ extern "C" HRESULT PackagesParseFromXml(
             }
         }
 
+        pPackage->fCanAffectRegistration = !pPackage->fPermanent;
+
         // parse payload references
         hr = ParsePayloadRefsFromXml(pPackage, pPayloads, pixnNode);
         ExitOnFailure(hr, "Failed to parse payload references.");
diff --git a/src/burn/engine/package.h b/src/burn/engine/package.h
index 91bad1bc..bbd74ac9 100644
--- a/src/burn/engine/package.h
+++ b/src/burn/engine/package.h
@@ -371,6 +371,7 @@ typedef struct _BURN_PACKAGE
         {
             LPWSTR sczDetectCondition;
             LPWSTR sczKB;
+            BOOL fUninstallable;
         } Msu;
     };
 } BURN_PACKAGE;
-- 
cgit v1.2.3-55-g6feb