aboutsummaryrefslogtreecommitdiff
path: root/src/burn/engine
diff options
context:
space:
mode:
Diffstat (limited to 'src/burn/engine')
-rw-r--r--src/burn/engine/approvedexe.cpp8
-rw-r--r--src/burn/engine/approvedexe.h2
-rw-r--r--src/burn/engine/bundlepackageengine.cpp6
-rw-r--r--src/burn/engine/elevation.cpp2
-rw-r--r--src/burn/engine/engine.mc7
-rw-r--r--src/burn/engine/exeengine.cpp295
-rw-r--r--src/burn/engine/package.h13
-rw-r--r--src/burn/engine/plan.cpp3
8 files changed, 295 insertions, 41 deletions
diff --git a/src/burn/engine/approvedexe.cpp b/src/burn/engine/approvedexe.cpp
index b9efd624..2a96868e 100644
--- a/src/burn/engine/approvedexe.cpp
+++ b/src/burn/engine/approvedexe.cpp
@@ -213,7 +213,7 @@ LExit:
213extern "C" HRESULT ApprovedExesVerifySecureLocation( 213extern "C" HRESULT ApprovedExesVerifySecureLocation(
214 __in BURN_CACHE* pCache, 214 __in BURN_CACHE* pCache,
215 __in BURN_VARIABLES* pVariables, 215 __in BURN_VARIABLES* pVariables,
216 __in BURN_LAUNCH_APPROVED_EXE* pLaunchApprovedExe 216 __in LPCWSTR wzExecutablePath
217 ) 217 )
218{ 218{
219 HRESULT hr = S_OK; 219 HRESULT hr = S_OK;
@@ -232,7 +232,7 @@ extern "C" HRESULT ApprovedExesVerifySecureLocation(
232 hr = VariableGetString(pVariables, wzSecureFolderVariable, &scz); 232 hr = VariableGetString(pVariables, wzSecureFolderVariable, &scz);
233 if (SUCCEEDED(hr)) 233 if (SUCCEEDED(hr))
234 { 234 {
235 hr = PathDirectoryContainsPath(scz, pLaunchApprovedExe->sczExecutablePath); 235 hr = PathDirectoryContainsPath(scz, wzExecutablePath);
236 if (S_OK == hr) 236 if (S_OK == hr)
237 { 237 {
238 ExitFunction(); 238 ExitFunction();
@@ -252,14 +252,14 @@ extern "C" HRESULT ApprovedExesVerifySecureLocation(
252 // If the package cache is redirected, hr is S_FALSE. 252 // If the package cache is redirected, hr is S_FALSE.
253 if (S_FALSE == hr) 253 if (S_FALSE == hr)
254 { 254 {
255 hr = PathDirectoryContainsPath(sczSecondary, pLaunchApprovedExe->sczExecutablePath); 255 hr = PathDirectoryContainsPath(sczSecondary, wzExecutablePath);
256 if (S_OK == hr) 256 if (S_OK == hr)
257 { 257 {
258 ExitFunction(); 258 ExitFunction();
259 } 259 }
260 } 260 }
261 261
262 hr = PathDirectoryContainsPath(scz, pLaunchApprovedExe->sczExecutablePath); 262 hr = PathDirectoryContainsPath(scz, wzExecutablePath);
263 if (S_OK == hr) 263 if (S_OK == hr)
264 { 264 {
265 ExitFunction(); 265 ExitFunction();
diff --git a/src/burn/engine/approvedexe.h b/src/burn/engine/approvedexe.h
index 8a3f6779..cbfda601 100644
--- a/src/burn/engine/approvedexe.h
+++ b/src/burn/engine/approvedexe.h
@@ -67,7 +67,7 @@ HRESULT ApprovedExesLaunch(
67HRESULT ApprovedExesVerifySecureLocation( 67HRESULT ApprovedExesVerifySecureLocation(
68 __in BURN_CACHE* pCache, 68 __in BURN_CACHE* pCache,
69 __in BURN_VARIABLES* pVariables, 69 __in BURN_VARIABLES* pVariables,
70 __in BURN_LAUNCH_APPROVED_EXE* pLaunchApprovedExe 70 __in LPCWSTR wzExecutablePath
71 ); 71 );
72 72
73 73
diff --git a/src/burn/engine/bundlepackageengine.cpp b/src/burn/engine/bundlepackageengine.cpp
index 6a0343bd..81279cf6 100644
--- a/src/burn/engine/bundlepackageengine.cpp
+++ b/src/burn/engine/bundlepackageengine.cpp
@@ -365,8 +365,7 @@ extern "C" HRESULT BundlePackageEnginePlanCalculatePackage(
365 break; 365 break;
366 366
367 default: 367 default:
368 hr = E_INVALIDARG; 368 ExitWithRootFailure(hr, E_INVALIDARG, "Invalid package current state: %d.", pPackage->currentState);
369 ExitOnRootFailure(hr, "Invalid package current state: %d.", pPackage->currentState);
370 } 369 }
371 370
372 // Calculate the rollback action if there is an execute action. 371 // Calculate the rollback action if there is an execute action.
@@ -413,8 +412,7 @@ extern "C" HRESULT BundlePackageEnginePlanCalculatePackage(
413 break; 412 break;
414 413
415 default: 414 default:
416 hr = E_INVALIDARG; 415 ExitWithRootFailure(hr, E_INVALIDARG, "Invalid package expected state.");
417 ExitOnRootFailure(hr, "Invalid package expected state.");
418 } 416 }
419 } 417 }
420 418
diff --git a/src/burn/engine/elevation.cpp b/src/burn/engine/elevation.cpp
index 75b24ec3..9c7cf89f 100644
--- a/src/burn/engine/elevation.cpp
+++ b/src/burn/engine/elevation.cpp
@@ -3858,7 +3858,7 @@ static HRESULT OnLaunchApprovedExe(
3858 hr = RegReadString(hKey, pApprovedExe->sczValueName, &pLaunchApprovedExe->sczExecutablePath); 3858 hr = RegReadString(hKey, pApprovedExe->sczValueName, &pLaunchApprovedExe->sczExecutablePath);
3859 ExitOnFailure(hr, "Failed to read the value for the approved exe path."); 3859 ExitOnFailure(hr, "Failed to read the value for the approved exe path.");
3860 3860
3861 hr = ApprovedExesVerifySecureLocation(pCache, pVariables, pLaunchApprovedExe); 3861 hr = ApprovedExesVerifySecureLocation(pCache, pVariables, pLaunchApprovedExe->sczExecutablePath);
3862 ExitOnFailure(hr, "Failed to verify the executable path is in a secure location: %ls", pLaunchApprovedExe->sczExecutablePath); 3862 ExitOnFailure(hr, "Failed to verify the executable path is in a secure location: %ls", pLaunchApprovedExe->sczExecutablePath);
3863 if (S_FALSE == hr) 3863 if (S_FALSE == hr)
3864 { 3864 {
diff --git a/src/burn/engine/engine.mc b/src/burn/engine/engine.mc
index 1c03145b..52524edb 100644
--- a/src/burn/engine/engine.mc
+++ b/src/burn/engine/engine.mc
@@ -331,6 +331,13 @@ Language=English
331Detected msi package with invalid version, product code: '%1!ls!', version: '%2!ls!' 331Detected msi package with invalid version, product code: '%1!ls!', version: '%2!ls!'
332. 332.
333 333
334MessageId=124
335Severity=Warning
336SymbolicName=MSG_DETECTED_EXE_PACKAGE_INVALID_VERSION
337Language=English
338Detected exe package with invalid version, arp id: '%1!ls!', version: '%2!ls!'
339.
340
334MessageId=151 341MessageId=151
335Severity=Error 342Severity=Error
336SymbolicName=MSG_FAILED_DETECT_PACKAGE 343SymbolicName=MSG_FAILED_DETECT_PACKAGE
diff --git a/src/burn/engine/exeengine.cpp b/src/burn/engine/exeengine.cpp
index 808577bc..3a64ecd8 100644
--- a/src/burn/engine/exeengine.cpp
+++ b/src/burn/engine/exeengine.cpp
@@ -2,6 +2,16 @@
2 2
3#include "precomp.h" 3#include "precomp.h"
4 4
5static HRESULT DetectArpEntry(
6 __in const BURN_PACKAGE* pPackage,
7 __out BOOTSTRAPPER_PACKAGE_STATE* pPackageState,
8 __out_opt LPWSTR* psczQuietUninstallString
9 );
10static HRESULT ParseArpUninstallString(
11 __in_z LPCWSTR wzArpUninstallString,
12 __inout LPWSTR* psczExecutablePath,
13 __inout LPWSTR* psczArguments
14 );
5 15
6// function definitions 16// function definitions
7 17
@@ -16,18 +26,73 @@ extern "C" HRESULT ExeEngineParsePackageFromXml(
16 IXMLDOMNode* pixnNode = NULL; 26 IXMLDOMNode* pixnNode = NULL;
17 LPWSTR scz = NULL; 27 LPWSTR scz = NULL;
18 28
19 // @DetectCondition 29 // @DetectionType
20 hr = XmlGetAttributeEx(pixnExePackage, L"DetectCondition", &pPackage->Exe.sczDetectCondition); 30 hr = XmlGetAttributeEx(pixnExePackage, L"DetectionType", &scz);
21 ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @DetectCondition."); 31 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @DetectionType.");
32
33 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"condition", -1))
34 {
35 pPackage->Exe.detectionType = BURN_EXE_DETECTION_TYPE_CONDITION;
36 }
37 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"arp", -1))
38 {
39 pPackage->Exe.detectionType = BURN_EXE_DETECTION_TYPE_ARP;
40 }
41 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"none", -1))
42 {
43 pPackage->Exe.detectionType = BURN_EXE_DETECTION_TYPE_NONE;
44 }
45 else
46 {
47 ExitWithRootFailure(hr, E_UNEXPECTED, "Invalid detection type: %ls", scz);
48 }
49
50 if (BURN_EXE_DETECTION_TYPE_CONDITION == pPackage->Exe.detectionType)
51 {
52 // @DetectCondition
53 hr = XmlGetAttributeEx(pixnExePackage, L"DetectCondition", &pPackage->Exe.sczDetectCondition);
54 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @DetectCondition.");
55
56 // @UninstallArguments
57 hr = XmlGetAttributeEx(pixnExePackage, L"UninstallArguments", &pPackage->Exe.sczUninstallArguments);
58 ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @UninstallArguments.");
59
60 // @Uninstallable
61 hr = XmlGetYesNoAttribute(pixnExePackage, L"Uninstallable", &pPackage->Exe.fUninstallable);
62 ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @Uninstallable.");
63 }
64 else if (BURN_EXE_DETECTION_TYPE_ARP == pPackage->Exe.detectionType)
65 {
66 // @ArpId
67 hr = XmlGetAttributeEx(pixnExePackage, L"ArpId", &scz);
68 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @ArpId.");
69
70 hr = PathConcatRelativeToBase(L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\", scz, &pPackage->Exe.sczArpKeyPath);
71 ExitOnFailure(hr, "Failed to build full key path.");
72
73 // @ArpDisplayVersion
74 hr = XmlGetAttributeEx(pixnExePackage, L"ArpDisplayVersion", &scz);
75 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @ArpDisplayVersion.");
76
77 hr = VerParseVersion(scz, 0, FALSE, &pPackage->Exe.pArpDisplayVersion);
78 ExitOnFailure(hr, "Failed to parse @ArpDisplayVersion: %ls", scz);
79
80 if (pPackage->Exe.pArpDisplayVersion->fInvalid)
81 {
82 LogId(REPORT_WARNING, MSG_MANIFEST_INVALID_VERSION, scz);
83 }
84
85 // @ArpWin64
86 hr = XmlGetYesNoAttribute(pixnExePackage, L"ArpWin64", &pPackage->Exe.fArpWin64);
87 ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @ArpWin64.");
88
89 pPackage->Exe.fUninstallable = TRUE;
90 }
22 91
23 // @InstallArguments 92 // @InstallArguments
24 hr = XmlGetAttributeEx(pixnExePackage, L"InstallArguments", &pPackage->Exe.sczInstallArguments); 93 hr = XmlGetAttributeEx(pixnExePackage, L"InstallArguments", &pPackage->Exe.sczInstallArguments);
25 ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @InstallArguments."); 94 ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @InstallArguments.");
26 95
27 // @UninstallArguments
28 hr = XmlGetAttributeEx(pixnExePackage, L"UninstallArguments", &pPackage->Exe.sczUninstallArguments);
29 ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @UninstallArguments.");
30
31 // @RepairArguments 96 // @RepairArguments
32 hr = XmlGetAttributeEx(pixnExePackage, L"RepairArguments", &pPackage->Exe.sczRepairArguments); 97 hr = XmlGetAttributeEx(pixnExePackage, L"RepairArguments", &pPackage->Exe.sczRepairArguments);
33 ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @RepairArguments."); 98 ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @RepairArguments.");
@@ -36,10 +101,6 @@ extern "C" HRESULT ExeEngineParsePackageFromXml(
36 hr = XmlGetYesNoAttribute(pixnExePackage, L"Repairable", &pPackage->Exe.fRepairable); 101 hr = XmlGetYesNoAttribute(pixnExePackage, L"Repairable", &pPackage->Exe.fRepairable);
37 ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @Repairable."); 102 ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @Repairable.");
38 103
39 // @Uninstallable
40 hr = XmlGetYesNoAttribute(pixnExePackage, L"Uninstallable", &pPackage->Exe.fUninstallable);
41 ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @Uninstallable.");
42
43 // @Bundle 104 // @Bundle
44 hr = XmlGetYesNoAttribute(pixnExePackage, L"Bundle", &pPackage->Exe.fBundle); 105 hr = XmlGetYesNoAttribute(pixnExePackage, L"Bundle", &pPackage->Exe.fBundle);
45 ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @Bundle."); 106 ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @Bundle.");
@@ -64,8 +125,7 @@ extern "C" HRESULT ExeEngineParsePackageFromXml(
64 } 125 }
65 else 126 else
66 { 127 {
67 hr = E_UNEXPECTED; 128 ExitWithRootFailure(hr, E_UNEXPECTED, "Invalid protocol type: %ls", scz);
68 ExitOnFailure(hr, "Invalid protocol type: %ls", scz);
69 } 129 }
70 } 130 }
71 131
@@ -91,6 +151,8 @@ extern "C" void ExeEnginePackageUninitialize(
91 ReleaseStr(pPackage->Exe.sczInstallArguments); 151 ReleaseStr(pPackage->Exe.sczInstallArguments);
92 ReleaseStr(pPackage->Exe.sczRepairArguments); 152 ReleaseStr(pPackage->Exe.sczRepairArguments);
93 ReleaseStr(pPackage->Exe.sczUninstallArguments); 153 ReleaseStr(pPackage->Exe.sczUninstallArguments);
154 ReleaseStr(pPackage->Exe.sczArpKeyPath);
155 ReleaseVerutilVersion(pPackage->Exe.pArpDisplayVersion);
94 ReleaseMem(pPackage->Exe.rgExitCodes); 156 ReleaseMem(pPackage->Exe.rgExitCodes);
95 157
96 // free command-line arguments 158 // free command-line arguments
@@ -126,15 +188,31 @@ extern "C" HRESULT ExeEngineDetectPackage(
126 HRESULT hr = S_OK; 188 HRESULT hr = S_OK;
127 BOOL fDetected = FALSE; 189 BOOL fDetected = FALSE;
128 190
129 // evaluate detect condition 191 switch (pPackage->Exe.detectionType)
130 if (pPackage->Exe.sczDetectCondition && *pPackage->Exe.sczDetectCondition)
131 { 192 {
132 hr = ConditionEvaluate(pVariables, pPackage->Exe.sczDetectCondition, &fDetected); 193 case BURN_EXE_DETECTION_TYPE_NONE:
133 ExitOnFailure(hr, "Failed to evaluate executable package detect condition."); 194 pPackage->currentState = BOOTSTRAPPER_PACKAGE_STATE_ABSENT;
134 } 195 break;
196 case BURN_EXE_DETECTION_TYPE_CONDITION:
197 // evaluate detect condition
198 if (pPackage->Exe.sczDetectCondition && *pPackage->Exe.sczDetectCondition)
199 {
200 hr = ConditionEvaluate(pVariables, pPackage->Exe.sczDetectCondition, &fDetected);
201 ExitOnFailure(hr, "Failed to evaluate EXE package detect condition.");
202 }
203
204 // update detect state
205 pPackage->currentState = fDetected ? BOOTSTRAPPER_PACKAGE_STATE_PRESENT : BOOTSTRAPPER_PACKAGE_STATE_ABSENT;
135 206
136 // update detect state 207 break;
137 pPackage->currentState = fDetected ? BOOTSTRAPPER_PACKAGE_STATE_PRESENT : BOOTSTRAPPER_PACKAGE_STATE_ABSENT; 208 case BURN_EXE_DETECTION_TYPE_ARP:
209 hr = DetectArpEntry(pPackage, &pPackage->currentState, NULL);
210 ExitOnFailure(hr, "Failed to detect EXE package by ArpEntry.");
211
212 break;
213 default:
214 ExitWithRootFailure(hr, E_INVALIDARG, "Unknown EXE package detection type: %d.", pPackage->Exe.detectionType);
215 }
138 216
139 if (pPackage->fCanAffectRegistration) 217 if (pPackage->fCanAffectRegistration)
140 { 218 {
@@ -187,6 +265,7 @@ extern "C" HRESULT ExeEnginePlanCalculatePackage(
187 } 265 }
188 break; 266 break;
189 267
268 case BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE: __fallthrough;
190 case BOOTSTRAPPER_PACKAGE_STATE_ABSENT: 269 case BOOTSTRAPPER_PACKAGE_STATE_ABSENT:
191 switch (pPackage->requested) 270 switch (pPackage->requested)
192 { 271 {
@@ -205,8 +284,7 @@ extern "C" HRESULT ExeEnginePlanCalculatePackage(
205 break; 284 break;
206 285
207 default: 286 default:
208 hr = E_INVALIDARG; 287 ExitWithRootFailure(hr, E_INVALIDARG, "Invalid package current state: %d.", pPackage->currentState);
209 ExitOnRootFailure(hr, "Invalid package current state: %d.", pPackage->currentState);
210 } 288 }
211 289
212 // Calculate the rollback action if there is an execute action. 290 // Calculate the rollback action if there is an execute action.
@@ -232,6 +310,7 @@ extern "C" HRESULT ExeEnginePlanCalculatePackage(
232 } 310 }
233 break; 311 break;
234 312
313 case BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE: __fallthrough;
235 case BOOTSTRAPPER_PACKAGE_STATE_ABSENT: 314 case BOOTSTRAPPER_PACKAGE_STATE_ABSENT:
236 switch (pPackage->requested) 315 switch (pPackage->requested)
237 { 316 {
@@ -251,8 +330,7 @@ extern "C" HRESULT ExeEnginePlanCalculatePackage(
251 break; 330 break;
252 331
253 default: 332 default:
254 hr = E_INVALIDARG; 333 ExitWithRootFailure(hr, E_INVALIDARG, "Invalid package expected state.");
255 ExitOnRootFailure(hr, "Invalid package expected state.");
256 } 334 }
257 } 335 }
258 336
@@ -356,10 +434,41 @@ extern "C" HRESULT ExeEngineExecutePackage(
356 LPWSTR sczUserArgs = NULL; 434 LPWSTR sczUserArgs = NULL;
357 LPWSTR sczUserArgsObfuscated = NULL; 435 LPWSTR sczUserArgsObfuscated = NULL;
358 LPWSTR sczCommandObfuscated = NULL; 436 LPWSTR sczCommandObfuscated = NULL;
437 LPWSTR sczArpUninstallString = NULL;
438 LPWSTR sczArpArguments = NULL;
439 BOOTSTRAPPER_PACKAGE_STATE applyState = BOOTSTRAPPER_PACKAGE_STATE_UNKNOWN;
359 HANDLE hExecutableFile = INVALID_HANDLE_VALUE; 440 HANDLE hExecutableFile = INVALID_HANDLE_VALUE;
360 DWORD dwExitCode = 0; 441 DWORD dwExitCode = 0;
361 BURN_PACKAGE* pPackage = pExecuteAction->exePackage.pPackage; 442 BURN_PACKAGE* pPackage = pExecuteAction->exePackage.pPackage;
362 BURN_PAYLOAD* pPackagePayload = pPackage->payloads.rgItems[0].pPayload; 443 BURN_PAYLOAD* pPackagePayload = pPackage->payloads.rgItems[0].pPayload;
444 LPCWSTR wzUninstallArguments = pPackage->Exe.sczUninstallArguments;
445
446 if (BURN_EXE_DETECTION_TYPE_ARP == pPackage->Exe.detectionType &&
447 (BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pExecuteAction->exePackage.action ||
448 BOOTSTRAPPER_ACTION_STATE_INSTALL == pExecuteAction->exePackage.action && fRollback))
449 {
450 hr = DetectArpEntry(pPackage, &applyState, &sczArpUninstallString);
451 ExitOnFailure(hr, "Failed to query ArpEntry for uninstall.");
452
453 if (BOOTSTRAPPER_PACKAGE_STATE_ABSENT == applyState && BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pExecuteAction->exePackage.action)
454 {
455 if (fRollback)
456 {
457 LogId(REPORT_STANDARD, MSG_ROLLBACK_PACKAGE_SKIPPED, pPackage->sczId, LoggingActionStateToString(pExecuteAction->exePackage.action), LoggingPackageStateToString(applyState));
458 }
459 else
460 {
461 LogId(REPORT_STANDARD, MSG_ATTEMPTED_UNINSTALL_ABSENT_PACKAGE, pPackage->sczId);
462 }
463
464 ExitFunction();
465 }
466 else if (BOOTSTRAPPER_PACKAGE_STATE_ABSENT != applyState && BOOTSTRAPPER_ACTION_STATE_INSTALL == pExecuteAction->exePackage.action)
467 {
468 LogId(REPORT_STANDARD, MSG_ROLLBACK_PACKAGE_SKIPPED, pPackage->sczId, LoggingActionStateToString(pExecuteAction->exePackage.action), LoggingPackageStateToString(applyState));
469 ExitFunction();
470 }
471 }
363 472
364 if (pPackage->Exe.fPseudoPackage && BURN_PAYLOAD_VERIFICATION_UPDATE_BUNDLE != pPackagePayload->verification) 473 if (pPackage->Exe.fPseudoPackage && BURN_PAYLOAD_VERIFICATION_UPDATE_BUNDLE != pPackagePayload->verification)
365 { 474 {
@@ -372,7 +481,30 @@ extern "C" HRESULT ExeEngineExecutePackage(
372 ExitOnFailure(hr, "Failed to build executable path."); 481 ExitOnFailure(hr, "Failed to build executable path.");
373 482
374 hr = PathGetDirectory(sczExecutablePath, &sczCachedDirectory); 483 hr = PathGetDirectory(sczExecutablePath, &sczCachedDirectory);
375 ExitOnFailure(hr, "Failed to get cached path for pseudo-package: %ls", pPackage->sczId); 484 ExitOnFailure(hr, "Failed to get parent directory for pseudo-package: %ls", pPackage->sczId);
485 }
486 else if (BURN_EXE_DETECTION_TYPE_ARP == pPackage->Exe.detectionType && BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pExecuteAction->exePackage.action)
487 {
488 ExitOnNull(sczArpUninstallString, hr, E_INVALIDARG, "QuietUninstallString is null.");
489
490 hr = ParseArpUninstallString(sczArpUninstallString, &sczExecutablePath, &sczArpArguments);
491 ExitOnFailure(hr, "Failed to parse QuietUninstallString: %ls.", sczArpUninstallString);
492
493 if (pPackage->fPerMachine)
494 {
495 hr = ApprovedExesVerifySecureLocation(pCache, pVariables, sczExecutablePath);
496 ExitOnFailure(hr, "Failed to verify the QuietUninstallString executable path is in a secure location: %ls", sczExecutablePath);
497 if (S_FALSE == hr)
498 {
499 LogStringLine(REPORT_STANDARD, "The QuietUninstallString executable path is not in a secure location: %ls", sczExecutablePath);
500 ExitFunction1(hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED));
501 }
502 }
503
504 hr = PathGetDirectory(sczExecutablePath, &sczCachedDirectory);
505 ExitOnFailure(hr, "Failed to get parent directory for QuietUninstallString executable path: %ls", sczExecutablePath);
506
507 wzUninstallArguments = sczArpArguments;
376 } 508 }
377 else 509 else
378 { 510 {
@@ -396,7 +528,7 @@ extern "C" HRESULT ExeEngineExecutePackage(
396 break; 528 break;
397 529
398 case BOOTSTRAPPER_ACTION_STATE_UNINSTALL: 530 case BOOTSTRAPPER_ACTION_STATE_UNINSTALL:
399 wzArguments = pPackage->Exe.sczUninstallArguments; 531 wzArguments = wzUninstallArguments;
400 break; 532 break;
401 533
402 case BOOTSTRAPPER_ACTION_STATE_REPAIR: 534 case BOOTSTRAPPER_ACTION_STATE_REPAIR:
@@ -404,8 +536,7 @@ extern "C" HRESULT ExeEngineExecutePackage(
404 break; 536 break;
405 537
406 default: 538 default:
407 hr = E_INVALIDARG; 539 ExitWithRootFailure(hr, E_INVALIDARG, "Invalid Exe package action: %d.", pExecuteAction->exePackage.action);
408 ExitOnFailure(hr, "Invalid Exe package action: %d.", pExecuteAction->exePackage.action);
409 } 540 }
410 541
411 // now add optional arguments 542 // now add optional arguments
@@ -443,8 +574,7 @@ extern "C" HRESULT ExeEngineExecutePackage(
443 break; 574 break;
444 575
445 default: 576 default:
446 hr = E_INVALIDARG; 577 ExitWithRootFailure(hr, E_INVALIDARG, "Invalid Exe package action: %d.", pExecuteAction->exePackage.action);
447 ExitOnFailure(hr, "Invalid Exe package action: %d.", pExecuteAction->exePackage.action);
448 } 578 }
449 } 579 }
450 } 580 }
@@ -524,6 +654,8 @@ LExit:
524 StrSecureZeroFreeString(sczUserArgs); 654 StrSecureZeroFreeString(sczUserArgs);
525 ReleaseStr(sczUserArgsObfuscated); 655 ReleaseStr(sczUserArgsObfuscated);
526 ReleaseStr(sczCommandObfuscated); 656 ReleaseStr(sczCommandObfuscated);
657 ReleaseStr(sczArpUninstallString);
658 ReleaseStr(sczArpArguments);
527 659
528 ReleaseFileHandle(hExecutableFile); 660 ReleaseFileHandle(hExecutableFile);
529 661
@@ -894,3 +1026,106 @@ extern "C" HRESULT ExeEngineHandleExitCode(
894//LExit: 1026//LExit:
895 return hr; 1027 return hr;
896} 1028}
1029
1030static HRESULT DetectArpEntry(
1031 __in const BURN_PACKAGE* pPackage,
1032 __out BOOTSTRAPPER_PACKAGE_STATE* pPackageState,
1033 __out_opt LPWSTR* psczQuietUninstallString
1034 )
1035{
1036 HRESULT hr = S_OK;
1037 HKEY hKey = NULL;
1038 VERUTIL_VERSION* pVersion = NULL;
1039 int nCompareResult = 0;
1040 HKEY hkRoot = pPackage->fPerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
1041 REG_KEY_BITNESS keyBitness = pPackage->Exe.fArpWin64 ? REG_KEY_64BIT : REG_KEY_32BIT;
1042
1043 *pPackageState = BOOTSTRAPPER_PACKAGE_STATE_ABSENT;
1044 if (psczQuietUninstallString)
1045 {
1046 ReleaseNullStr(*psczQuietUninstallString);
1047 }
1048
1049 hr = RegOpenEx(hkRoot, pPackage->Exe.sczArpKeyPath, KEY_READ, keyBitness, &hKey);
1050 if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr || HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
1051 {
1052 ExitFunction1(hr = S_OK);
1053 }
1054 ExitOnFailure(hr, "Failed to open registry key: %ls.", pPackage->Exe.sczArpKeyPath);
1055
1056 hr = RegReadWixVersion(hKey, L"DisplayVersion", &pVersion);
1057 if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
1058 {
1059 ExitFunction1(hr = S_OK);
1060 }
1061 ExitOnFailure(hr, "Failed to read DisplayVersion.");
1062
1063 if (pVersion->fInvalid)
1064 {
1065 LogId(REPORT_WARNING, MSG_DETECTED_EXE_PACKAGE_INVALID_VERSION, pPackage->Exe.sczArpKeyPath, pVersion->sczVersion);
1066 }
1067
1068 hr = VerCompareParsedVersions(pPackage->Exe.pArpDisplayVersion, pVersion, &nCompareResult);
1069 ExitOnFailure(hr, "Failed to compare versions.");
1070
1071 if (nCompareResult < 0)
1072 {
1073 *pPackageState = BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE;
1074 }
1075 else if (nCompareResult > 0)
1076 {
1077 *pPackageState = BOOTSTRAPPER_PACKAGE_STATE_ABSENT;
1078 }
1079 else
1080 {
1081 *pPackageState = BOOTSTRAPPER_PACKAGE_STATE_PRESENT;
1082 }
1083
1084 if (psczQuietUninstallString)
1085 {
1086 hr = RegReadString(hKey, L"QuietUninstallString", psczQuietUninstallString);
1087 if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
1088 {
1089 hr = S_OK;
1090 }
1091 ExitOnFailure(hr, "Failed to read QuietUninstallString.");
1092 }
1093
1094LExit:
1095 ReleaseRegKey(hKey);
1096 ReleaseVerutilVersion(pVersion);
1097
1098 return hr;
1099}
1100
1101static HRESULT ParseArpUninstallString(
1102 __in_z LPCWSTR wzArpUninstallString,
1103 __inout LPWSTR* psczExecutablePath,
1104 __inout LPWSTR* psczArguments
1105 )
1106{
1107 HRESULT hr = S_OK;
1108 int argc = 0;
1109 LPWSTR* argv = NULL;
1110
1111 hr = AppParseCommandLine(wzArpUninstallString, &argc, &argv);
1112 ExitOnFailure(hr, "Failed to parse uninstall string as command line: %ls.", wzArpUninstallString);
1113 ExitOnNull(argc, hr, E_INVALIDARG, "Uninstall string must contain an executable path.");
1114
1115 hr = StrAllocString(psczExecutablePath, argv[0], 0);
1116 ExitOnFailure(hr, "Failed to copy executable path for ArpCommand.");
1117
1118 for (int i = 1; i < argc; ++i)
1119 {
1120 hr = AppAppendCommandLineArgument(psczArguments, argv[i]);
1121 ExitOnFailure(hr, "Failed to append argument for ArpCommand.");
1122 }
1123
1124LExit:
1125 if (argv)
1126 {
1127 AppFreeCommandLineArgs(argv);
1128 }
1129
1130 return hr;
1131}
diff --git a/src/burn/engine/package.h b/src/burn/engine/package.h
index 3ec77baf..85f34de5 100644
--- a/src/burn/engine/package.h
+++ b/src/burn/engine/package.h
@@ -16,6 +16,13 @@ typedef _BURN_PACKAGE BURN_PACKAGE;
16 16
17const DWORD BURN_PACKAGE_INVALID_PATCH_INDEX = 0x80000000; 17const DWORD BURN_PACKAGE_INVALID_PATCH_INDEX = 0x80000000;
18 18
19enum BURN_EXE_DETECTION_TYPE
20{
21 BURN_EXE_DETECTION_TYPE_NONE,
22 BURN_EXE_DETECTION_TYPE_CONDITION,
23 BURN_EXE_DETECTION_TYPE_ARP,
24};
25
19enum BURN_EXE_EXIT_CODE_TYPE 26enum BURN_EXE_EXIT_CODE_TYPE
20{ 27{
21 BURN_EXE_EXIT_CODE_TYPE_NONE, 28 BURN_EXE_EXIT_CODE_TYPE_NONE,
@@ -338,6 +345,12 @@ typedef struct _BURN_PACKAGE
338 } Bundle; 345 } Bundle;
339 struct 346 struct
340 { 347 {
348 BURN_EXE_DETECTION_TYPE detectionType;
349
350 BOOL fArpWin64;
351 LPWSTR sczArpKeyPath;
352 VERUTIL_VERSION* pArpDisplayVersion;
353
341 LPWSTR sczDetectCondition; 354 LPWSTR sczDetectCondition;
342 LPWSTR sczInstallArguments; 355 LPWSTR sczInstallArguments;
343 LPWSTR sczRepairArguments; 356 LPWSTR sczRepairArguments;
diff --git a/src/burn/engine/plan.cpp b/src/burn/engine/plan.cpp
index 52bf6298..419d3272 100644
--- a/src/burn/engine/plan.cpp
+++ b/src/burn/engine/plan.cpp
@@ -2798,7 +2798,8 @@ static BOOL NeedsCache(
2798{ 2798{
2799 BOOTSTRAPPER_ACTION_STATE action = fExecute ? pPackage->execute : pPackage->rollback; 2799 BOOTSTRAPPER_ACTION_STATE action = fExecute ? pPackage->execute : pPackage->rollback;
2800 // TODO: bundles could theoretically use package cache 2800 // TODO: bundles could theoretically use package cache
2801 if (BURN_PACKAGE_TYPE_BUNDLE == pPackage->type || BURN_PACKAGE_TYPE_EXE == pPackage->type) // Bundle and Exe packages require the package for all operations (even uninstall). 2801 if (BURN_PACKAGE_TYPE_BUNDLE == pPackage->type || // Bundle and Exe packages require the package for all operations (even uninstall).
2802 BURN_PACKAGE_TYPE_EXE == pPackage->type && BURN_EXE_DETECTION_TYPE_ARP != pPackage->Exe.detectionType)
2802 { 2803 {
2803 return BOOTSTRAPPER_ACTION_STATE_NONE != action; 2804 return BOOTSTRAPPER_ACTION_STATE_NONE != action;
2804 } 2805 }