From 8c77de737aaea1b4857c724c730446bca8da2dd0 Mon Sep 17 00:00:00 2001
From: Sean Hall <r.sean.hall@gmail.com>
Date: Fri, 16 Apr 2021 10:48:38 -0500
Subject: Elevate for CacheVerifyContainer/Payload.

---
 src/engine/apply.cpp     |  15 +++---
 src/engine/cache.cpp     |  68 ++++++++++++++++--------
 src/engine/elevation.cpp | 136 ++++++++++++++++++++++++++++++++++++++++++++++-
 src/engine/elevation.h   |   7 +++
 src/engine/engine.mc     |  14 +++++
 5 files changed, 209 insertions(+), 31 deletions(-)

(limited to 'src/engine')

diff --git a/src/engine/apply.cpp b/src/engine/apply.cpp
index f40b3841..0eb8a710 100644
--- a/src/engine/apply.cpp
+++ b/src/engine/apply.cpp
@@ -538,6 +538,9 @@ extern "C" HRESULT ApplyCache(
 
             if (!pPackage->fPerMachine && !cacheContext.wzLayoutDirectory)
             {
+                hr = CacheGetCompletedPath(FALSE, pPackage->sczCacheId, &pPackage->sczCacheFolder);
+                ExitOnFailure(hr, "Failed to get cached path for package with cache id: %ls", pPackage->sczCacheId);
+
                 cacheContext.hPipe = INVALID_HANDLE_VALUE;
             }
 
@@ -800,12 +803,6 @@ static HRESULT ApplyCachePackage(
     HRESULT hr = S_OK;
     BOOTSTRAPPER_CACHEPACKAGECOMPLETE_ACTION cachePackageCompleteAction = BOOTSTRAPPER_CACHEPACKAGECOMPLETE_ACTION_NONE;
 
-    if (!pPackage->sczCacheFolder && !pContext->wzLayoutDirectory)
-    {
-        hr = CacheGetCompletedPath(pPackage->fPerMachine, pPackage->sczCacheId, &pPackage->sczCacheFolder);
-        ExitOnFailure(hr, "Failed to get cached path for package with cache id: %ls", pPackage->sczCacheId);
-    }
-
     for (;;)
     {
         hr = UserExperienceOnCachePackageBegin(pContext->pUX, pPackage->sczId, pPackage->payloads.cPayloads, pPackage->payloads.qwTotalSize);
@@ -1038,7 +1035,11 @@ static HRESULT ApplyCacheVerifyContainerOrPayload(
     hr = UserExperienceOnCacheContainerOrPayloadVerifyBegin(pContext->pUX, wzPackageOrContainerId, wzPayloadId);
     ExitOnRootFailure(hr, "BA aborted cache container or payload verify begin.");
 
-    if (pContainer)
+    if (INVALID_HANDLE_VALUE != pContext->hPipe)
+    {
+        hr = ElevationCacheVerifyContainerOrPayload(pContext->hPipe, pContainer, pPackage, pPayload, pContext->wzLayoutDirectory);
+    }
+    else if (pContainer)
     {
         hr = CacheVerifyContainer(pContainer, pContext->wzLayoutDirectory);
     }
diff --git a/src/engine/cache.cpp b/src/engine/cache.cpp
index 2299d26d..9aa94d1d 100644
--- a/src/engine/cache.cpp
+++ b/src/engine/cache.cpp
@@ -59,11 +59,13 @@ static HRESULT TransferWorkingPathToUnverifiedPath(
     );
 static HRESULT VerifyFileAgainstContainer(
     __in BURN_CONTAINER* pContainer,
-    __in_z LPCWSTR wzVerifyPath
+    __in_z LPCWSTR wzVerifyPath,
+    __in BOOL fAlreadyCached
     );
 static HRESULT VerifyFileAgainstPayload(
     __in BURN_PAYLOAD* pPayload,
-    __in_z LPCWSTR wzVerifyPath
+    __in_z LPCWSTR wzVerifyPath,
+    __in BOOL fAlreadyCached
     );
 static HRESULT ResetPathPermissions(
     __in BOOL fPerMachine,
@@ -896,19 +898,11 @@ extern "C" HRESULT CacheCompletePayload(
     ExitOnFailure(hr, "Failed to concat complete cached path.");
 
     // If the cached file matches what we expected, we're good.
-    hr = VerifyFileAgainstPayload(pPayload, sczCachedPath);
+    hr = VerifyFileAgainstPayload(pPayload, sczCachedPath, TRUE);
     if (SUCCEEDED(hr))
     {
-        ::DecryptFileW(sczCachedPath, 0);  // Let's try to make sure it's not encrypted.
-        LogId(REPORT_STANDARD, MSG_VERIFIED_EXISTING_PAYLOAD, pPayload->sczKey, sczCachedPath);
         ExitFunction();
     }
-    else if (E_PATHNOTFOUND != hr && E_FILENOTFOUND != hr)
-    {
-        LogErrorId(hr, MSG_FAILED_VERIFY_PAYLOAD, pPayload->sczKey, sczCachedPath, NULL);
-
-        FileEnsureDelete(sczCachedPath); // if the file existed but did not verify correctly, make it go away.
-    }
 
     hr = CreateUnverifiedPath(fPerMachine, pPayload->sczKey, &sczUnverifiedPayloadPath);
     ExitOnFailure(hr, "Failed to create unverified path.");
@@ -928,14 +922,8 @@ extern "C" HRESULT CacheCompletePayload(
     hr = ResetPathPermissions(fPerMachine, sczUnverifiedPayloadPath);
     ExitOnFailure(hr, "Failed to reset permissions on unverified cached payload: %ls", pPayload->sczKey);
 
-    hr = VerifyFileAgainstPayload(pPayload, sczUnverifiedPayloadPath);
-    if (FAILED(hr))
-    {
-        LogErrorId(hr, MSG_FAILED_VERIFY_PAYLOAD, pPayload->sczKey, sczUnverifiedPayloadPath, NULL);
-
-        FileEnsureDelete(sczUnverifiedPayloadPath); // if the file did not verify correctly, make it go away.
-        ExitFunction();
-    }
+    hr = VerifyFileAgainstPayload(pPayload, sczUnverifiedPayloadPath, FALSE);
+    LogExitOnFailure(hr, MSG_FAILED_VERIFY_PAYLOAD, "Failed to verify payload: %ls at path: %ls", pPayload->sczKey, sczUnverifiedPayloadPath, NULL);
 
     LogId(REPORT_STANDARD, MSG_VERIFIED_ACQUIRED_PAYLOAD, pPayload->sczKey, sczUnverifiedPayloadPath, fMove ? "moving" : "copying", sczCachedPath);
 
@@ -963,7 +951,7 @@ extern "C" HRESULT CacheVerifyContainer(
     hr = PathConcat(wzCachedDirectory, pContainer->sczFilePath, &sczCachedPath);
     ExitOnFailure(hr, "Failed to concat complete cached path.");
 
-    hr = VerifyFileAgainstContainer(pContainer, sczCachedPath);
+    hr = VerifyFileAgainstContainer(pContainer, sczCachedPath, TRUE);
 
 LExit:
     ReleaseStr(sczCachedPath);
@@ -982,7 +970,7 @@ extern "C" HRESULT CacheVerifyPayload(
     hr = PathConcat(wzCachedDirectory, pPayload->sczFilePath, &sczCachedPath);
     ExitOnFailure(hr, "Failed to concat complete cached path.");
 
-    hr = VerifyFileAgainstPayload(pPayload, sczCachedPath);
+    hr = VerifyFileAgainstPayload(pPayload, sczCachedPath, TRUE);
 
 LExit:
     ReleaseStr(sczCachedPath);
@@ -1460,7 +1448,8 @@ LExit:
 
 static HRESULT VerifyFileAgainstContainer(
     __in BURN_CONTAINER* pContainer,
-    __in_z LPCWSTR wzVerifyPath
+    __in_z LPCWSTR wzVerifyPath,
+    __in BOOL fAlreadyCached
     )
 {
     HRESULT hr = S_OK;
@@ -1484,15 +1473,32 @@ static HRESULT VerifyFileAgainstContainer(
         ExitOnFailure(hr, "Failed to verify hash of container: %ls", pContainer->sczId);
     }
 
+    if (fAlreadyCached)
+    {
+        LogId(REPORT_STANDARD, MSG_VERIFIED_EXISTING_CONTAINER, pContainer->sczId, wzVerifyPath);
+        ::DecryptFileW(wzVerifyPath, 0);  // Let's try to make sure it's not encrypted.
+    }
+
 LExit:
     ReleaseFileHandle(hFile);
 
+    if (FAILED(hr) && E_PATHNOTFOUND != hr && E_FILENOTFOUND != hr)
+    {
+        if (fAlreadyCached)
+        {
+            LogErrorId(hr, MSG_FAILED_VERIFY_CONTAINER, pContainer->sczId, wzVerifyPath, NULL);
+        }
+
+        FileEnsureDelete(wzVerifyPath); // if the file existed but did not verify correctly, make it go away.
+    }
+
     return hr;
 }
 
 static HRESULT VerifyFileAgainstPayload(
     __in BURN_PAYLOAD* pPayload,
-    __in_z LPCWSTR wzVerifyPath
+    __in_z LPCWSTR wzVerifyPath,
+    __in BOOL fAlreadyCached
     )
 {
     HRESULT hr = S_OK;
@@ -1516,9 +1522,25 @@ static HRESULT VerifyFileAgainstPayload(
         ExitOnFailure(hr, "Failed to verify hash of payload: %ls", pPayload->sczKey);
     }
 
+    if (fAlreadyCached)
+    {
+        LogId(REPORT_STANDARD, MSG_VERIFIED_EXISTING_PAYLOAD, pPayload->sczKey, wzVerifyPath);
+        ::DecryptFileW(wzVerifyPath, 0);  // Let's try to make sure it's not encrypted.
+    }
+
 LExit:
     ReleaseFileHandle(hFile);
 
+    if (FAILED(hr) && E_PATHNOTFOUND != hr && E_FILENOTFOUND != hr)
+    {
+        if (fAlreadyCached)
+        {
+            LogErrorId(hr, MSG_FAILED_VERIFY_PAYLOAD, pPayload->sczKey, wzVerifyPath, NULL);
+        }
+
+        FileEnsureDelete(wzVerifyPath); // if the file existed but did not verify correctly, make it go away.
+    }
+
     return hr;
 }
 
diff --git a/src/engine/elevation.cpp b/src/engine/elevation.cpp
index d37907cf..2dd61a81 100644
--- a/src/engine/elevation.cpp
+++ b/src/engine/elevation.cpp
@@ -16,6 +16,7 @@ typedef enum _BURN_ELEVATION_MESSAGE_TYPE
     BURN_ELEVATION_MESSAGE_TYPE_SAVE_STATE,
     BURN_ELEVATION_MESSAGE_TYPE_LAYOUT_BUNDLE,
     BURN_ELEVATION_MESSAGE_TYPE_CACHE_OR_LAYOUT_CONTAINER_OR_PAYLOAD,
+    BURN_ELEVATION_MESSAGE_TYPE_CACHE_VERIFY_CONTAINER_OR_PAYLOAD,
     BURN_ELEVATION_MESSAGE_TYPE_CACHE_CLEANUP,
     BURN_ELEVATION_MESSAGE_TYPE_PROCESS_DEPENDENT_REGISTRATION,
     BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_EXE_PACKAGE,
@@ -176,6 +177,13 @@ static HRESULT OnCacheOrLayoutContainerOrPayload(
     __in BYTE* pbData,
     __in DWORD cbData
     );
+static HRESULT OnCacheVerifyContainerOrPayload(
+    __in BURN_CONTAINERS* pContainers,
+    __in BURN_PACKAGES* pPackages,
+    __in BURN_PAYLOADS* pPayloads,
+    __in BYTE* pbData,
+    __in DWORD cbData
+    );
 static void OnCacheCleanup(
     __in_z LPCWSTR wzBundleId
     );
@@ -657,6 +665,44 @@ LExit:
     return hr;
 }
 
+extern "C" HRESULT ElevationCacheVerifyContainerOrPayload(
+    __in HANDLE hPipe,
+    __in_opt BURN_CONTAINER* pContainer,
+    __in_opt BURN_PACKAGE* pPackage,
+    __in_opt BURN_PAYLOAD* pPayload,
+    __in_z_opt LPCWSTR wzLayoutDirectory
+    )
+{
+    HRESULT hr = S_OK;
+    BYTE* pbData = NULL;
+    SIZE_T cbData = 0;
+    DWORD dwResult = 0;
+
+    // serialize message data
+    hr = BuffWriteString(&pbData, &cbData, pContainer ? pContainer->sczId : NULL);
+    ExitOnFailure(hr, "Failed to write container id to message buffer.");
+
+    hr = BuffWriteString(&pbData, &cbData, pPackage ? pPackage->sczId : NULL);
+    ExitOnFailure(hr, "Failed to write package id to message buffer.");
+
+    hr = BuffWriteString(&pbData, &cbData, pPayload ? pPayload->sczKey : NULL);
+    ExitOnFailure(hr, "Failed to write payload id to message buffer.");
+
+    hr = BuffWriteString(&pbData, &cbData, wzLayoutDirectory);
+    ExitOnFailure(hr, "Failed to write layout directory to message buffer.");
+
+    // send message
+    hr = PipeSendMessage(hPipe, BURN_ELEVATION_MESSAGE_TYPE_CACHE_VERIFY_CONTAINER_OR_PAYLOAD, pbData, cbData, NULL, NULL, &dwResult);
+    ExitOnFailure(hr, "Failed to send BURN_ELEVATION_MESSAGE_TYPE_CACHE_VERIFY_CONTAINER_OR_PAYLOAD message to per-machine process.");
+
+    hr = (HRESULT)dwResult;
+
+LExit:
+    ReleaseBuffer(pbData);
+
+    return hr;
+}
+
 /*******************************************************************
  ElevationCacheCleanup - 
 
@@ -1724,6 +1770,10 @@ static HRESULT ProcessElevatedChildCacheMessage(
         hrResult = OnCacheOrLayoutContainerOrPayload(pContext->pContainers, pContext->pPackages, pContext->pPayloads, (BYTE*)pMsg->pvData, pMsg->cbData);
         break;
 
+    case BURN_ELEVATION_MESSAGE_TYPE_CACHE_VERIFY_CONTAINER_OR_PAYLOAD:
+        hrResult = OnCacheVerifyContainerOrPayload(pContext->pContainers, pContext->pPackages, pContext->pPayloads, (BYTE*)pMsg->pvData, pMsg->cbData);
+        break;
+
     case BURN_ELEVATION_MESSAGE_TYPE_CACHE_CLEANUP:
         OnCacheCleanup(pContext->pRegistration->sczId);
         hrResult = S_OK;
@@ -2062,7 +2112,7 @@ static HRESULT OnCacheOrLayoutContainerOrPayload(
 
     // Deserialize message data.
     hr = BuffReadString(pbData, cbData, &iData, &scz);
-    ExitOnFailure(hr, "Failed to read package id.");
+    ExitOnFailure(hr, "Failed to read container id.");
 
     if (scz && *scz)
     {
@@ -2135,6 +2185,90 @@ LExit:
     return hr;
 }
 
+static HRESULT OnCacheVerifyContainerOrPayload(
+    __in BURN_CONTAINERS* pContainers,
+    __in BURN_PACKAGES* pPackages,
+    __in BURN_PAYLOADS* pPayloads,
+    __in BYTE* pbData,
+    __in DWORD cbData
+    )
+{
+    HRESULT hr = S_OK;
+    SIZE_T iData = 0;
+    LPWSTR scz = NULL;
+    BURN_CONTAINER* pContainer = NULL;
+    BURN_PACKAGE* pPackage = NULL;
+    BURN_PAYLOAD* pPayload = NULL;
+    LPWSTR sczCacheDirectory = NULL;
+
+    // Deserialize message data.
+    hr = BuffReadString(pbData, cbData, &iData, &scz);
+    ExitOnFailure(hr, "Failed to read container id.");
+
+    if (scz && *scz)
+    {
+        hr = ContainerFindById(pContainers, scz, &pContainer);
+        ExitOnFailure(hr, "Failed to find container: %ls", scz);
+    }
+
+    hr = BuffReadString(pbData, cbData, &iData, &scz);
+    ExitOnFailure(hr, "Failed to read package id.");
+
+    if (scz && *scz)
+    {
+        hr = PackageFindById(pPackages, scz, &pPackage);
+        ExitOnFailure(hr, "Failed to find package: %ls", scz);
+    }
+
+    hr = BuffReadString(pbData, cbData, &iData, &scz);
+    ExitOnFailure(hr, "Failed to read payload id.");
+
+    if (scz && *scz)
+    {
+        hr = PayloadFindById(pPayloads, scz, &pPayload);
+        ExitOnFailure(hr, "Failed to find payload: %ls", scz);
+    }
+
+    hr = BuffReadString(pbData, cbData, &iData, &sczCacheDirectory);
+    ExitOnFailure(hr, "Failed to read layout directory.");
+
+    if (!sczCacheDirectory || !*sczCacheDirectory)
+    {
+        if (!pPackage)
+        {
+            hr = E_INVALIDARG;
+            ExitOnRootFailure(hr, "Invalid data passed to cache verify payload.");
+        }
+
+        hr = CacheGetCompletedPath(TRUE, pPackage->sczCacheId, &sczCacheDirectory);
+        ExitOnFailure(hr, "Failed to get cached path for package with cache id: %ls", pPackage->sczCacheId);
+    }
+
+    if (pContainer)
+    {
+        Assert(!pPackage);
+        Assert(!pPayload);
+
+        hr = CacheVerifyContainer(pContainer, sczCacheDirectory);
+    }
+    else if (pPayload)
+    {
+        hr = CacheVerifyPayload(pPayload, sczCacheDirectory);
+    }
+    else
+    {
+        hr = E_INVALIDARG;
+        ExitOnRootFailure(hr, "Invalid data passed to cache or layout payload.");
+    }
+    // Nothing should be logged on failure.
+
+LExit:
+    ReleaseStr(sczCacheDirectory);
+    ReleaseStr(scz);
+
+    return hr;
+}
+
 static void OnCacheCleanup(
     __in_z LPCWSTR wzBundleId
     )
diff --git a/src/engine/elevation.h b/src/engine/elevation.h
index 9ce8cef9..da67e3f3 100644
--- a/src/engine/elevation.h
+++ b/src/engine/elevation.h
@@ -64,6 +64,13 @@ HRESULT ElevationCacheOrLayoutContainerOrPayload(
     __in_z LPCWSTR wzUnverifiedPath,
     __in BOOL fMove
     );
+HRESULT ElevationCacheVerifyContainerOrPayload(
+    __in HANDLE hPipe,
+    __in_opt BURN_CONTAINER* pContainer,
+    __in_opt BURN_PACKAGE* pPackage,
+    __in_opt BURN_PAYLOAD* pPayload,
+    __in_z_opt LPCWSTR wzLayoutDirectory
+    );
 HRESULT ElevationCacheCleanup(
     __in HANDLE hPipe
     );
diff --git a/src/engine/engine.mc b/src/engine/engine.mc
index 0e19d3bb..6e0695bc 100644
--- a/src/engine/engine.mc
+++ b/src/engine/engine.mc
@@ -478,6 +478,13 @@ Language=English
 Acquired payload: %1!ls! to working path: %2!ls! from: %4!ls!.
 .
 
+MessageId=303
+Severity=Success
+SymbolicName=MSG_VERIFIED_EXISTING_CONTAINER
+Language=English
+Verified existing container: %1!ls! at path: %2!ls!.
+.
+
 MessageId=304
 Severity=Success
 SymbolicName=MSG_VERIFIED_EXISTING_PAYLOAD
@@ -724,6 +731,13 @@ Language=English
 Acquiring package: %1!ls!, payload: %2!ls!, %3!hs! from: %4!ls!
 .
 
+MessageId=339
+Severity=Error
+SymbolicName=MSG_FAILED_VERIFY_CONTAINER
+Language=English
+Failed to verify container: %2!ls! at path: %3!ls!, error: %1!ls!. Deleting file.
+.
+
 MessageId=347
 Severity=Warning
 SymbolicName=MSG_APPLY_RETRYING_CONTAINER
-- 
cgit v1.2.3-55-g6feb