@joebigelow / wix-1 / commits / cdba28de

Add argument and policy setting to set Burn's base working directory.

Fixes #5856

Sean Hall committed Aug 3, 2021 at 18:06 UTC cdba28de1ee229369b254c62bc58cf2f001899a3
14 files changed +503 -133
src/burn/engine/cache.cpp
+56 -9
@@ -14,6 +14,10 @@ static HRESULT CacheVerifyPayloadSignature(
14 __in_z LPCWSTR wzUnverifiedPayloadPath,
15 __in HANDLE hFile
16 );
17 +static HRESULT CalculateBaseWorkingFolder(
18 + __in BURN_ENGINE_COMMAND* pInternalCommand,
19 + __inout_z LPWSTR* psczBaseWorkingFolder
20 + );
21 static HRESULT CalculateWorkingFolder(
22 __in BURN_CACHE* pCache,
23 __in BURN_ENGINE_COMMAND* pInternalCommand
@@ -1337,28 +1341,71 @@ extern "C" void CacheUninitialize(
1341
1342 // Internal functions.
1343
1340 -static HRESULT CalculateWorkingFolder(
1341 - __in BURN_CACHE* pCache,
1342 - __in BURN_ENGINE_COMMAND* pInternalCommand
1344 +static HRESULT CalculateBaseWorkingFolder(
1345 + __in BURN_ENGINE_COMMAND* pInternalCommand,
1346 + __inout_z LPWSTR* psczBaseWorkingFolder
1347 )
1348 {
1349 HRESULT hr = S_OK;
1346 - RPC_STATUS rs = RPC_S_OK;
1347 - LPWSTR sczTempPath = NULL;
1348 - UUID guid = {};
1349 - WCHAR wzGuid[39];
1350
1351 + ReleaseNullStr(*psczBaseWorkingFolder);
1352 +
1353 + // The value from the command line takes precedence.
1354 + if (pInternalCommand->sczWorkingDirectory)
1355 + {
1356 + hr = PathExpand(psczBaseWorkingFolder, pInternalCommand->sczWorkingDirectory, PATH_EXPAND_FULLPATH);
1357 + ExitOnFailure(hr, "Failed to expand engine working directory from command-line: '%ls'", pInternalCommand->sczWorkingDirectory);
1358 +
1359 + ExitFunction();
1360 + }
1361 +
1362 + // The base working folder can be specified through policy,
1363 + // but only use it if elevated because it should be secured against non-admin users.
1364 if (pInternalCommand->fInitiallyElevated)
1365 {
1353 - hr = PathGetSystemTempPath(&sczTempPath);
1366 + hr = PolcReadString(POLICY_BURN_REGISTRY_PATH, L"EngineWorkingDirectory", NULL, psczBaseWorkingFolder);
1367 + ExitOnFailure(hr, "Failed to read EngineWorkingDirectory policy directory.");
1368 +
1369 + if (*psczBaseWorkingFolder)
1370 + {
1371 + // PolcReadString is supposed to automatically expand REG_EXPAND_SZ values.
1372 + ExitFunction();
1373 + }
1374 + }
1375 +
1376 + // Default to the temp path specified in environment variables, but need to use system temp path for security reasons if running elevated.
1377 + if (pInternalCommand->fInitiallyElevated)
1378 + {
1379 + hr = PathGetSystemTempPath(psczBaseWorkingFolder);
1380 ExitOnFailure(hr, "Failed to get system temp folder path for working folder.");
1381 }
1382 else
1383 {
1358 - hr = PathGetTempPath(&sczTempPath);
1384 + hr = PathGetTempPath(psczBaseWorkingFolder);
1385 ExitOnFailure(hr, "Failed to get temp folder path for working folder.");
1386 }
1387
1388 +LExit:
1389 + return hr;
1390 +}
1391 +
1392 +static HRESULT CalculateWorkingFolder(
1393 + __in BURN_CACHE* pCache,
1394 + __in BURN_ENGINE_COMMAND* pInternalCommand
1395 + )
1396 +{
1397 + HRESULT hr = S_OK;
1398 + RPC_STATUS rs = RPC_S_OK;
1399 + LPWSTR sczTempPath = NULL;
1400 + UUID guid = {};
1401 + WCHAR wzGuid[39];
1402 +
1403 + hr = CalculateBaseWorkingFolder(pInternalCommand, &sczTempPath);
1404 + ExitOnFailure(hr, "Failed to get base engine working directory.");
1405 +
1406 + hr = PathBackslashTerminate(&sczTempPath);
1407 + ExitOnFailure(hr, "Failed to backslashify base engine working directory.");
1408 +
1409 rs = ::UuidCreate(&guid);
1410 hr = HRESULT_FROM_RPC(rs);
1411 ExitOnFailure(hr, "Failed to create working folder guid.");
src/burn/engine/core.cpp
+144 -7
@@ -22,6 +22,23 @@ static HRESULT CoreRecreateCommandLine(
22 __in BOOTSTRAPPER_RELATION_TYPE relationType,
23 __in BOOL fPassthrough
24 );
25 +static HRESULT AppendEscapedArgumentToCommandLine(
26 + __in_z LPCWSTR wzEscapedArgument,
27 + __deref_inout_z LPWSTR* psczCommandLine,
28 + __deref_inout_z_opt LPWSTR* psczObfuscatedCommandLine
29 + );
30 +static HRESULT EscapeAndAppendArgumentToCommandLineFormatted(
31 + __deref_inout_z LPWSTR* psczCommandLine,
32 + __deref_inout_z_opt LPWSTR* psczObfuscatedCommandLine,
33 + __in __format_string LPCWSTR wzFormat,
34 + ...
35 + );
36 +static HRESULT EscapeAndAppendArgumentToCommandLineFormattedArgs(
37 + __deref_inout_z LPWSTR* psczCommandLine,
38 + __deref_inout_z_opt LPWSTR* psczObfuscatedCommandLine,
39 + __in __format_string LPCWSTR wzFormat,
40 + __in va_list args
41 + );
42 static HRESULT AppendLayoutToCommandLine(
43 __in BOOTSTRAPPER_ACTION action,
44 __in_z LPCWSTR wzLayoutDirectory,
@@ -207,11 +224,12 @@ extern "C" HRESULT CoreInitializeConstants(
224 for (DWORD i = 0; i < pEngineState->packages.cPackages; ++i)
225 {
226 BURN_PACKAGE* pPackage = pEngineState->packages.rgPackages + i;
210 -
227 +
228 if (BURN_PACKAGE_TYPE_EXE == pPackage->type && BURN_EXE_PROTOCOL_TYPE_BURN == pPackage->Exe.protocol) // TODO: Don't assume exePackages with burn protocol are bundles.
229 {
230 // Pass along any ancestors and ourself to prevent infinite loops.
231 pPackage->Exe.wzAncestors = pRegistration->sczBundlePackageAncestors;
232 + pPackage->Exe.wzEngineWorkingDirectory = pInternalCommand->sczWorkingDirectory;
233 }
234 }
235
@@ -1001,6 +1019,9 @@ static HRESULT CoreRecreateCommandLine(
1019 ExitOnFailure(hr, "Failed to append ancestors to command-line.");
1020 }
1021
1022 + hr = CoreAppendEngineWorkingDirectoryToCommandLine(pInternalCommand->sczWorkingDirectory, psczCommandLine, NULL);
1023 + ExitOnFailure(hr, "Failed to append the custom working directory to command-line.");
1024 +
1025 if (wzRelationTypeCommandLine)
1026 {
1027 hr = StrAllocConcatFormatted(psczCommandLine, L" /%ls", wzRelationTypeCommandLine);
@@ -1060,7 +1081,7 @@ extern "C" HRESULT CoreCreateCleanRoomCommandLine(
1081 hr = StrAllocConcatFormatted(psczCommandLine, L" /%ls", wzLogParameter);
1082 ExitOnFailure(hr, "Failed to append logging switch.");
1083
1063 - hr = PathCommandLineAppend(psczCommandLine, pInternalCommand->sczLogFile);
1084 + hr = AppAppendCommandLineArgument(psczCommandLine, pInternalCommand->sczLogFile);
1085 ExitOnFailure(hr, "Failed to append custom log path.");
1086 }
1087
@@ -1091,7 +1112,7 @@ extern "C" HRESULT CoreCreateCleanRoomCommandLine(
1112 hr = StrAllocConcat(psczCommandLine, L" /originalsource", 0);
1113 ExitOnFailure(hr, "Failed to append /originalsource.");
1114
1094 - hr = PathCommandLineAppend(psczCommandLine, pInternalCommand->sczOriginalSource);
1115 + hr = AppAppendCommandLineArgument(psczCommandLine, pInternalCommand->sczOriginalSource);
1116 ExitOnFailure(hr, "Failed to append original source.");
1117 }
1118
@@ -1256,6 +1277,28 @@ LExit:
1277 return hr;
1278 }
1279
1280 +extern "C" HRESULT CoreAppendEngineWorkingDirectoryToCommandLine(
1281 + __in_z_opt LPCWSTR wzEngineWorkingDirectory,
1282 + __deref_inout_z LPWSTR* psczCommandLine,
1283 + __deref_inout_z_opt LPWSTR* psczObfuscatedCommandLine
1284 + )
1285 +{
1286 + HRESULT hr = S_OK;
1287 + LPWSTR sczArgument = NULL;
1288 +
1289 + if (wzEngineWorkingDirectory)
1290 + {
1291 + hr = EscapeAndAppendArgumentToCommandLineFormatted(psczCommandLine, psczObfuscatedCommandLine, L"-%ls=%ls", BURN_COMMANDLINE_SWITCH_WORKING_DIRECTORY, wzEngineWorkingDirectory);
1292 + ExitOnFailure(hr, "Failed to append the custom working directory to the command line.");
1293 + }
1294 +
1295 +LExit:
1296 + ReleaseStr(sczArgument);
1297 +
1298 + return hr;
1299 +}
1300 +
1301 +
1302 extern "C" void CoreCleanup(
1303 __in BURN_ENGINE_STATE* pEngineState
1304 )
@@ -1678,6 +1721,27 @@ extern "C" HRESULT CoreParseCommandLine(
1721 ExitOnFailure(hr, "Failed to allocate the list of ancestors.");
1722 }
1723 }
1724 + else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], lstrlenW(BURN_COMMANDLINE_SWITCH_WORKING_DIRECTORY), BURN_COMMANDLINE_SWITCH_WORKING_DIRECTORY, lstrlenW(BURN_COMMANDLINE_SWITCH_WORKING_DIRECTORY)))
1725 + {
1726 + // Get a pointer to the next character after the switch.
1727 + LPCWSTR wzParam = &argv[i][1 + lstrlenW(BURN_COMMANDLINE_SWITCH_WORKING_DIRECTORY)];
1728 + if (L'=' != wzParam[0])
1729 + {
1730 + fInvalidCommandLine = TRUE;
1731 + TraceLog(E_INVALIDARG, "Invalid switch: %ls", argv[i]);
1732 + }
1733 + else if (L'\0' == wzParam[1])
1734 + {
1735 + // Need to grab the current directory here since this is passed on to other processes.
1736 + hr = DirGetCurrent(&pInternalCommand->sczWorkingDirectory);
1737 + ExitOnFailure(hr, "Failed to get current directory for custom working directory.");
1738 + }
1739 + else
1740 + {
1741 + hr = StrAllocString(&pInternalCommand->sczWorkingDirectory, wzParam + 1, 0);
1742 + ExitOnFailure(hr, "Failed to allocate the custom working directory.");
1743 + }
1744 + }
1745 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], lstrlenW(BURN_COMMANDLINE_SWITCH_FILEHANDLE_ATTACHED), BURN_COMMANDLINE_SWITCH_FILEHANDLE_ATTACHED, lstrlenW(BURN_COMMANDLINE_SWITCH_FILEHANDLE_ATTACHED)))
1746 {
1747 LPCWSTR wzParam = &argv[i][2 + lstrlenW(BURN_COMMANDLINE_SWITCH_FILEHANDLE_ATTACHED)];
@@ -1807,6 +1871,79 @@ LExit:
1871
1872 // internal helper functions
1873
1874 +static HRESULT AppendEscapedArgumentToCommandLine(
1875 + __in_z LPCWSTR wzEscapedArgument,
1876 + __deref_inout_z LPWSTR* psczCommandLine,
1877 + __deref_inout_z_opt LPWSTR* psczObfuscatedCommandLine
1878 + )
1879 +{
1880 + HRESULT hr = S_OK;
1881 +
1882 + // If there is already data in the command line,
1883 + // append a space before appending the argument.
1884 + if (*psczCommandLine && **psczCommandLine)
1885 + {
1886 + hr = StrAllocConcatSecure(psczCommandLine, L" ", 0);
1887 + ExitOnFailure(hr, "Failed to append space to command line with existing data.");
1888 + }
1889 +
1890 + hr = StrAllocConcatSecure(psczCommandLine, wzEscapedArgument, 0);
1891 + ExitOnFailure(hr, "Failed to append escaped command line argument.");
1892 +
1893 + if (psczObfuscatedCommandLine)
1894 + {
1895 + if (*psczObfuscatedCommandLine && **psczObfuscatedCommandLine)
1896 + {
1897 + hr = StrAllocConcat(psczObfuscatedCommandLine, L" ", 0);
1898 + ExitOnFailure(hr, "Failed to append space to obfuscated command line with existing data.");
1899 + }
1900 +
1901 + hr = StrAllocConcat(psczObfuscatedCommandLine, wzEscapedArgument, 0);
1902 + ExitOnFailure(hr, "Failed to append escaped argument to obfuscated command line.");
1903 + }
1904 +
1905 +LExit:
1906 + return hr;
1907 +}
1908 +
1909 +static HRESULT EscapeAndAppendArgumentToCommandLineFormatted(
1910 + __deref_inout_z LPWSTR* psczCommandLine,
1911 + __deref_inout_z_opt LPWSTR* psczObfuscatedCommandLine,
1912 + __in __format_string LPCWSTR wzFormat,
1913 + ...
1914 + )
1915 +{
1916 + HRESULT hr = S_OK;
1917 + va_list args;
1918 +
1919 + va_start(args, wzFormat);
1920 + hr = EscapeAndAppendArgumentToCommandLineFormattedArgs(psczCommandLine, psczObfuscatedCommandLine, wzFormat, args);
1921 + va_end(args);
1922 +
1923 + return hr;
1924 +}
1925 +
1926 +static HRESULT EscapeAndAppendArgumentToCommandLineFormattedArgs(
1927 + __deref_inout_z LPWSTR* psczCommandLine,
1928 + __deref_inout_z_opt LPWSTR* psczObfuscatedCommandLine,
1929 + __in __format_string LPCWSTR wzFormat,
1930 + __in va_list args
1931 + )
1932 +{
1933 + HRESULT hr = S_OK;
1934 + LPWSTR sczArgument = NULL;
1935 +
1936 + hr = AppEscapeCommandLineArgumentFormattedArgs(&sczArgument, wzFormat, args);
1937 + ExitOnFailure(hr, "Failed to escape the argument for the command line.");
1938 +
1939 + hr = AppendEscapedArgumentToCommandLine(sczArgument, psczCommandLine, psczObfuscatedCommandLine);
1940 +
1941 +LExit:
1942 + ReleaseStr(sczArgument);
1943 +
1944 + return hr;
1945 +}
1946 +
1947 static HRESULT AppendLayoutToCommandLine(
1948 __in BOOTSTRAPPER_ACTION action,
1949 __in_z LPCWSTR wzLayoutDirectory,
@@ -1822,7 +1959,7 @@ static HRESULT AppendLayoutToCommandLine(
1959
1960 if (wzLayoutDirectory)
1961 {
1825 - hr = PathCommandLineAppend(psczCommandLine, wzLayoutDirectory);
1962 + hr = AppAppendCommandLineArgument(psczCommandLine, wzLayoutDirectory);
1963 ExitOnFailure(hr, "Failed to append layout directory.");
1964 }
1965 }
@@ -1883,16 +2020,16 @@ static HRESULT GetSanitizedCommandLine(
2020 }
2021
2022 // Remember command-line switch to pass off to BA.
1886 - PathCommandLineAppend(&pCommand->wzCommandLine, argv[i]);
2023 + AppAppendCommandLineArgument(&pCommand->wzCommandLine, argv[i]);
2024 }
2025
2026 if (fHidden)
2027 {
1891 - PathCommandLineAppend(psczSanitizedCommandLine, sczSanitizedArgument);
2028 + AppAppendCommandLineArgument(psczSanitizedCommandLine, sczSanitizedArgument);
2029 }
2030 else
2031 {
1895 - PathCommandLineAppend(psczSanitizedCommandLine, argv[i]);
2032 + AppAppendCommandLineArgument(psczSanitizedCommandLine, argv[i]);
2033 }
2034 }
2035
src/burn/engine/core.h
+7
@@ -14,6 +14,7 @@ const LPCWSTR BURN_POLICY_REGISTRY_PATH = L"WiX\\Burn";
14 const LPCWSTR BURN_COMMANDLINE_SWITCH_PARENT = L"parent";
15 const LPCWSTR BURN_COMMANDLINE_SWITCH_PARENT_NONE = L"parent:none";
16 const LPCWSTR BURN_COMMANDLINE_SWITCH_CLEAN_ROOM = L"burn.clean.room";
17 +const LPCWSTR BURN_COMMANDLINE_SWITCH_WORKING_DIRECTORY = L"burn.working.directory";
18 const LPCWSTR BURN_COMMANDLINE_SWITCH_ELEVATED = L"burn.elevated";
19 const LPCWSTR BURN_COMMANDLINE_SWITCH_EMBEDDED = L"burn.embedded";
20 const LPCWSTR BURN_COMMANDLINE_SWITCH_RUNONCE = L"burn.runonce";
@@ -99,6 +100,7 @@ typedef struct _BURN_ENGINE_COMMAND
100
101 LPWSTR sczSourceProcessPath;
102 LPWSTR sczOriginalSource;
103 + LPWSTR sczWorkingDirectory;
104
105 DWORD dwLoggingAttributes;
106 LPWSTR sczLogFile;
@@ -254,6 +256,11 @@ HRESULT CoreAppendSplashScreenWindowToCommandLine(
256 __in_opt HWND hwndSplashScreen,
257 __deref_inout_z LPWSTR* psczCommandLine
258 );
259 +HRESULT CoreAppendEngineWorkingDirectoryToCommandLine(
260 + __in_z_opt LPCWSTR wzEngineWorkingDirectory,
261 + __deref_inout_z LPWSTR* psczCommandLine,
262 + __deref_inout_z_opt LPWSTR* psczObfuscatedCommandLine
263 + );
264 void CoreCleanup(
265 __in BURN_ENGINE_STATE* pEngineState
266 );
src/burn/engine/elevation.cpp
+14
@@ -852,6 +852,9 @@ extern "C" HRESULT ElevationExecuteExePackage(
852 hr = BuffWriteString(&pbData, &cbData, pExecuteAction->exePackage.sczAncestors);
853 ExitOnFailure(hr, "Failed to write the list of ancestors to the message buffer.");
854
855 + hr = BuffWriteString(&pbData, &cbData, pExecuteAction->exePackage.sczEngineWorkingDirectory);
856 + ExitOnFailure(hr, "Failed to write the custom working directory to the message buffer.");
857 +
858 hr = VariableSerialize(pVariables, FALSE, &pbData, &cbData);
859 ExitOnFailure(hr, "Failed to write variables.");
860
@@ -2476,6 +2479,7 @@ static HRESULT OnExecuteExePackage(
2479 BURN_EXECUTE_ACTION executeAction = { };
2480 LPWSTR sczIgnoreDependencies = NULL;
2481 LPWSTR sczAncestors = NULL;
2482 + LPWSTR sczEngineWorkingDirectory = NULL;
2483 BOOTSTRAPPER_APPLY_RESTART exeRestart = BOOTSTRAPPER_APPLY_RESTART_NONE;
2484
2485 executeAction.type = BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE;
@@ -2496,6 +2500,9 @@ static HRESULT OnExecuteExePackage(
2500 hr = BuffReadString(pbData, cbData, &iData, &sczAncestors);
2501 ExitOnFailure(hr, "Failed to read the list of ancestors.");
2502
2503 + hr = BuffReadString(pbData, cbData, &iData, &sczEngineWorkingDirectory);
2504 + ExitOnFailure(hr, "Failed to read the custom working directory.");
2505 +
2506 hr = VariableDeserialize(pVariables, FALSE, pbData, cbData, &iData);
2507 ExitOnFailure(hr, "Failed to read variables.");
2508
@@ -2520,11 +2527,18 @@ static HRESULT OnExecuteExePackage(
2527 ExitOnFailure(hr, "Failed to allocate the list of ancestors.");
2528 }
2529
2530 + if (sczEngineWorkingDirectory && *sczEngineWorkingDirectory)
2531 + {
2532 + hr = StrAllocString(&executeAction.exePackage.sczEngineWorkingDirectory, sczEngineWorkingDirectory, 0);
2533 + ExitOnFailure(hr, "Failed to allocate the custom working directory.");
2534 + }
2535 +
2536 // Execute EXE package.
2537 hr = ExeEngineExecutePackage(&executeAction, pCache, pVariables, static_cast<BOOL>(dwRollback), GenericExecuteMessageHandler, hPipe, &exeRestart);
2538 ExitOnFailure(hr, "Failed to execute EXE package.");
2539
2540 LExit:
2541 + ReleaseStr(sczEngineWorkingDirectory);
2542 ReleaseStr(sczAncestors);
2543 ReleaseStr(sczIgnoreDependencies);
2544 ReleaseStr(sczPackage);
src/burn/engine/engine.cpp
+1
@@ -401,6 +401,7 @@ static void UninitializeEngineState(
401 ReleaseStr(pEngineState->internalCommand.sczLogFile);
402 ReleaseStr(pEngineState->internalCommand.sczOriginalSource);
403 ReleaseStr(pEngineState->internalCommand.sczSourceProcessPath);
404 + ReleaseStr(pEngineState->internalCommand.sczWorkingDirectory);
405
406 ReleaseStr(pEngineState->log.sczExtension);
407 ReleaseStr(pEngineState->log.sczPrefix);
src/burn/engine/exeengine.cpp
+9
@@ -308,6 +308,12 @@ extern "C" HRESULT ExeEnginePlanAddPackage(
308 ExitOnFailure(hr, "Failed to allocate the list of ancestors.");
309 }
310
311 + if (pPackage->Exe.wzEngineWorkingDirectory)
312 + {
313 + hr = StrAllocString(&pAction->exePackage.sczEngineWorkingDirectory, pPackage->Exe.wzEngineWorkingDirectory, 0);
314 + ExitOnFailure(hr, "Failed to allocate the custom working directory.");
315 + }
316 +
317 LoggingSetPackageVariable(pPackage, NULL, FALSE, pLog, pVariables, NULL); // ignore errors.
318 }
319
@@ -488,6 +494,9 @@ extern "C" HRESULT ExeEngineExecutePackage(
494
495 if (BURN_EXE_PROTOCOL_TYPE_BURN == pPackage->Exe.protocol)
496 {
497 + hr = CoreAppendEngineWorkingDirectoryToCommandLine(pExecuteAction->exePackage.sczEngineWorkingDirectory, &sczCommand, &sczCommandObfuscated);
498 + ExitOnFailure(hr, "Failed to append the custom working directory to the exepackage command line.");
499 +
500 hr = CoreAppendFileHandleSelfToCommandLine(sczExecutablePath, &hExecutableFile, &sczCommand, &sczCommandObfuscated);
501 ExitOnFailure(hr, "Failed to append %ls", BURN_COMMANDLINE_SWITCH_FILEHANDLE_SELF);
502 }
src/burn/engine/package.h
+1
@@ -267,6 +267,7 @@ typedef struct _BURN_PACKAGE
267 LPWSTR sczUninstallArguments;
268 LPWSTR sczIgnoreDependencies;
269 LPCWSTR wzAncestors; // points directly into engine state.
270 + LPCWSTR wzEngineWorkingDirectory; // points directly into engine state.
271
272 BOOL fPseudoBundle;
273
src/burn/engine/plan.cpp
+2
@@ -266,6 +266,7 @@ extern "C" void PlanUninitializeExecuteAction(
266 case BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE:
267 ReleaseStr(pExecuteAction->exePackage.sczIgnoreDependencies);
268 ReleaseStr(pExecuteAction->exePackage.sczAncestors);
269 + ReleaseStr(pExecuteAction->exePackage.sczEngineWorkingDirectory);
270 break;
271
272 case BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE:
@@ -1282,6 +1283,7 @@ extern "C" HRESULT PlanRelatedBundlesBegin(
1283
1284 // Pass along any ancestors and ourself to prevent infinite loops.
1285 pRelatedBundle->package.Exe.wzAncestors = pRegistration->sczBundlePackageAncestors;
1286 + pRelatedBundle->package.Exe.wzEngineWorkingDirectory = pPlan->pInternalCommand->sczWorkingDirectory;
1287
1288 hr = PlanDefaultRelatedBundleRequestState(relationType, pRelatedBundle->relationType, pPlan->action, pRegistration->pVersion, pRelatedBundle->pVersion, &pRelatedBundle->package.requested);
1289 ExitOnFailure(hr, "Failed to get default request state for related bundle.");
src/burn/engine/plan.h
+1
@@ -164,6 +164,7 @@ typedef struct _BURN_EXECUTE_ACTION
164 BOOTSTRAPPER_ACTION_STATE action;
165 LPWSTR sczIgnoreDependencies;
166 LPWSTR sczAncestors;
167 + LPWSTR sczEngineWorkingDirectory;
168 } exePackage;
169 struct
170 {
src/libs/dutil/WixToolset.DUtil/apputil.cpp
+227 -4
@@ -20,7 +20,18 @@ const DWORD PRIVATE_LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800;
20 typedef BOOL(WINAPI *LPFN_SETDEFAULTDLLDIRECTORIES)(DWORD);
21 typedef BOOL(WINAPI *LPFN_SETDLLDIRECTORYW)(LPCWSTR);
22
23 -extern "C" void DAPI AppFreeCommandLineArgs(
23 +/********************************************************************
24 +EscapeCommandLineArgument - encodes wzArgument such that
25 + ::CommandLineToArgv() will parse it back unaltered. If no escaping
26 + was required, *psczEscaped is NULL.
27 +
28 +********************************************************************/
29 +static HRESULT EscapeCommandLineArgument(
30 + __in_z LPCWSTR wzArgument,
31 + __out_z LPWSTR* psczEscaped
32 + );
33 +
34 +DAPI_(void) AppFreeCommandLineArgs(
35 __in LPWSTR* argv
36 )
37 {
@@ -34,7 +45,7 @@ AppInitialize - initializes the standard safety precautions for an
45 installation application.
46
47 ********************************************************************/
37 -extern "C" void DAPI AppInitialize(
48 +DAPI_(void) AppInitialize(
49 __in_ecount(cSafelyLoadSystemDlls) LPCWSTR rgsczSafelyLoadSystemDlls[],
50 __in DWORD cSafelyLoadSystemDlls
51 )
@@ -85,12 +96,12 @@ extern "C" void DAPI AppInitialize(
96 }
97 }
98
88 -extern "C" void DAPI AppInitializeUnsafe()
99 +DAPI_(void) AppInitializeUnsafe()
100 {
101 ::HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
102 }
103
93 -extern "C" DAPI_(HRESULT) AppParseCommandLine(
104 +DAPI_(HRESULT) AppParseCommandLine(
105 __in LPCWSTR wzCommandLine,
106 __in int* pArgc,
107 __in LPWSTR** pArgv
@@ -122,3 +133,215 @@ LExit:
133
134 return hr;
135 }
136 +
137 +DAPI_(HRESULT) AppAppendCommandLineArgument(
138 + __deref_inout_z LPWSTR* psczCommandLine,
139 + __in_z LPCWSTR wzArgument
140 + )
141 +{
142 + HRESULT hr = S_OK;
143 + LPWSTR sczQuotedArg = NULL;
144 +
145 + hr = EscapeCommandLineArgument(wzArgument, &sczQuotedArg);
146 + AppExitOnFailure(hr, "Failed to escape command line argument.");
147 +
148 + // If there is already data in the command line,
149 + // append a space before appending the argument.
150 + if (*psczCommandLine && **psczCommandLine)
151 + {
152 + hr = StrAllocConcatSecure(psczCommandLine, L" ", 0);
153 + AppExitOnFailure(hr, "Failed to append space to command line with existing data.");
154 + }
155 +
156 + hr = StrAllocConcatSecure(psczCommandLine, sczQuotedArg ? sczQuotedArg : wzArgument, 0);
157 + AppExitOnFailure(hr, "Failed to copy command line argument.");
158 +
159 +LExit:
160 + ReleaseStr(sczQuotedArg);
161 +
162 + return hr;
163 +}
164 +
165 +DAPIV_(HRESULT) AppAppendCommandLineArgumentFormatted(
166 + __deref_inout_z LPWSTR* psczCommandLine,
167 + __in __format_string LPCWSTR wzFormat,
168 + ...
169 + )
170 +{
171 + HRESULT hr = S_OK;
172 + va_list args;
173 +
174 + va_start(args, wzFormat);
175 + hr = AppAppendCommandLineArgumentFormattedArgs(psczCommandLine, wzFormat, args);
176 + va_end(args);
177 +
178 + return hr;
179 +}
180 +
181 +DAPI_(HRESULT) AppAppendCommandLineArgumentFormattedArgs(
182 + __deref_inout_z LPWSTR* psczCommandLine,
183 + __in __format_string LPCWSTR wzFormat,
184 + __in va_list args
185 + )
186 +{
187 + HRESULT hr = S_OK;
188 + LPWSTR sczQuotedArg = NULL;
189 +
190 + hr = AppEscapeCommandLineArgumentFormattedArgs(&sczQuotedArg, wzFormat, args);
191 + AppExitOnFailure(hr, "Failed to escape command line argument.");
192 +
193 + // If there is already data in the command line,
194 + // append a space before appending the argument.
195 + if (*psczCommandLine && **psczCommandLine)
196 + {
197 + hr = StrAllocConcatSecure(psczCommandLine, L" ", 0);
198 + AppExitOnFailure(hr, "Failed to append space to command line with existing data.");
199 + }
200 +
201 + hr = StrAllocConcatSecure(psczCommandLine, sczQuotedArg, 0);
202 + AppExitOnFailure(hr, "Failed to copy command line argument.");
203 +
204 +LExit:
205 + ReleaseStr(sczQuotedArg);
206 +
207 + return hr;
208 +}
209 +
210 +DAPIV_(HRESULT) AppEscapeCommandLineArgumentFormatted(
211 + __deref_inout_z LPWSTR* psczEscapedArgument,
212 + __in __format_string LPCWSTR wzFormat,
213 + ...
214 + )
215 +{
216 + HRESULT hr = S_OK;
217 + va_list args;
218 +
219 + va_start(args, wzFormat);
220 + hr = AppEscapeCommandLineArgumentFormattedArgs(psczEscapedArgument, wzFormat, args);
221 + va_end(args);
222 +
223 + return hr;
224 +}
225 +
226 +DAPI_(HRESULT) AppEscapeCommandLineArgumentFormattedArgs(
227 + __deref_inout_z LPWSTR* psczEscapedArgument,
228 + __in __format_string LPCWSTR wzFormat,
229 + __in va_list args
230 + )
231 +{
232 + HRESULT hr = S_OK;
233 + LPWSTR sczFormattedArg = NULL;
234 + LPWSTR sczQuotedArg = NULL;
235 +
236 + hr = StrAllocFormattedArgsSecure(&sczFormattedArg, wzFormat, args);
237 + AppExitOnFailure(hr, "Failed to format command line argument.");
238 +
239 + hr = EscapeCommandLineArgument(sczFormattedArg, &sczQuotedArg);
240 + AppExitOnFailure(hr, "Failed to escape command line argument.");
241 +
242 + if (sczQuotedArg)
243 + {
244 + *psczEscapedArgument = sczQuotedArg;
245 + sczQuotedArg = NULL;
246 + }
247 + else
248 + {
249 + *psczEscapedArgument = sczFormattedArg;
250 + sczFormattedArg = NULL;
251 + }
252 +
253 +LExit:
254 + ReleaseStr(sczFormattedArg);
255 + ReleaseStr(sczQuotedArg);
256 +
257 + return hr;
258 +}
259 +
260 +static HRESULT EscapeCommandLineArgument(
261 + __in_z LPCWSTR wzArgument,
262 + __out_z LPWSTR* psczEscaped
263 + )
264 +{
265 + HRESULT hr = S_OK;
266 + BOOL fRequiresQuoting = FALSE;
267 + SIZE_T cMaxEscapedSize = 0;
268 +
269 + *psczEscaped = NULL;
270 +
271 + // Loop through the argument determining if it needs to be quoted and what the maximum
272 + // size would be if there are escape characters required.
273 + for (LPCWSTR pwz = wzArgument; *pwz; ++pwz)
274 + {
275 + // Arguments with whitespace need quoting.
276 + if (L' ' == *pwz || L'\t' == *pwz || L'\n' == *pwz || L'\v' == *pwz)
277 + {
278 + fRequiresQuoting = TRUE;
279 + }
280 + else if (L'"' == *pwz) // quotes need quoting and sometimes escaping.
281 + {
282 + fRequiresQuoting = TRUE;
283 + ++cMaxEscapedSize;
284 + }
285 + else if (L'\\' == *pwz) // some backslashes need escaping, so we'll count them all to make sure there is room.
286 + {
287 + ++cMaxEscapedSize;
288 + }
289 +
290 + ++cMaxEscapedSize;
291 + }
292 +
293 + // If we found anything in the argument that requires our argument to be quoted
294 + if (fRequiresQuoting)
295 + {
296 + hr = StrAlloc(psczEscaped, cMaxEscapedSize + 3); // plus three for the start and end quote plus null terminator.
297 + AppExitOnFailure(hr, "Failed to allocate argument to be quoted.");
298 +
299 + LPCWSTR pwz = wzArgument;
300 + LPWSTR pwzQuoted = *psczEscaped;
301 +
302 + *pwzQuoted = L'"';
303 + ++pwzQuoted;
304 + while (*pwz)
305 + {
306 + DWORD dwBackslashes = 0;
307 + while (L'\\' == *pwz)
308 + {
309 + ++dwBackslashes;
310 + ++pwz;
311 + }
312 +
313 + // Escape all backslashes at the end of the string.
314 + if (!*pwz)
315 + {
316 + dwBackslashes *= 2;
317 + }
318 + else if (L'"' == *pwz) // escape all backslashes before the quote and escape the quote itself.
319 + {
320 + dwBackslashes = dwBackslashes * 2 + 1;
321 + }
322 + // the backslashes don't have to be escaped.
323 +
324 + // Add the appropriate number of backslashes
325 + for (DWORD i = 0; i < dwBackslashes; ++i)
326 + {
327 + *pwzQuoted = L'\\';
328 + ++pwzQuoted;
329 + }
330 +
331 + // If there is a character, add it after all the escaped backslashes
332 + if (*pwz)
333 + {
334 + *pwzQuoted = *pwz;
335 + ++pwz;
336 + ++pwzQuoted;
337 + }
338 + }
339 +
340 + *pwzQuoted = L'"';
341 + ++pwzQuoted;
342 + *pwzQuoted = L'\0'; // ensure the arg is null terminated.
343 + }
344 +
345 +LExit:
346 + return hr;
347 +}
src/libs/dutil/WixToolset.DUtil/inc/apputil.h
+40 -1
@@ -34,12 +34,51 @@ AppParseCommandLine - parses the command line using CommandLineToArgvW.
34 by calling AppFreeCommandLineArgs.
35
36 ********************************************************************/
37 -DAPI_(HRESULT) AppParseCommandLine(
37 +HRESULT DAPI AppParseCommandLine(
38 __in LPCWSTR wzCommandLine,
39 __in int* argc,
40 __in LPWSTR** pArgv
41 );
42
43 +/*******************************************************************
44 + AppAppendCommandLineArgument - appends a command line argument on to a
45 + string such that ::CommandLineToArgv() will shred them correctly
46 + (i.e. quote arguments with spaces in them).
47 +********************************************************************/
48 +HRESULT DAPI AppAppendCommandLineArgument(
49 + __deref_inout_z LPWSTR* psczCommandLine,
50 + __in_z LPCWSTR wzArgument
51 + );
52 +
53 +HRESULT DAPIV AppAppendCommandLineArgumentFormatted(
54 + __deref_inout_z LPWSTR* psczCommandLine,
55 + __in __format_string LPCWSTR wzFormat,
56 + ...
57 + );
58 +
59 +HRESULT DAPI AppAppendCommandLineArgumentFormattedArgs(
60 + __deref_inout_z LPWSTR* psczCommandLine,
61 + __in __format_string LPCWSTR wzFormat,
62 + __in va_list args
63 + );
64 +
65 +/********************************************************************
66 +AppEscapeCommandLineArgumentFormatted - formats a string and then
67 + escapes it such that ::CommandLineToArgv() will parse it back unaltered.
68 +
69 +********************************************************************/
70 +HRESULT DAPIV AppEscapeCommandLineArgumentFormatted(
71 + __deref_inout_z LPWSTR* psczEscapedArgument,
72 + __in __format_string LPCWSTR wzFormat,
73 + ...
74 + );
75 +
76 +HRESULT DAPI AppEscapeCommandLineArgumentFormattedArgs(
77 + __deref_inout_z LPWSTR* psczEscapedArgument,
78 + __in __format_string LPCWSTR wzFormat,
79 + __in va_list args
80 + );
81 +
82 #ifdef __cplusplus
83 }
84 #endif
src/libs/dutil/WixToolset.DUtil/inc/pathutil.h
-10
@@ -13,16 +13,6 @@ typedef enum PATH_EXPAND
13 } PATH_EXPAND;
14
15
16 -/*******************************************************************
17 - PathCommandLineAppend - appends a command line argument on to a
18 - string such that ::CommandLineToArgv() will shred them correctly
19 - (i.e. quote arguments with spaces in them).
20 -********************************************************************/
21 -DAPI_(HRESULT) PathCommandLineAppend(
22 - __deref_inout_z LPWSTR* psczCommandLine,
23 - __in_z LPCWSTR wzArgument
24 - );
25 -
16 /*******************************************************************
17 PathFile - returns a pointer to the file part of the path.
18 ********************************************************************/
src/libs/dutil/WixToolset.DUtil/pathutil.cpp
-102
@@ -21,108 +21,6 @@
21 #define PATH_GOOD_ENOUGH 64
22
23
24 -DAPI_(HRESULT) PathCommandLineAppend(
25 - __deref_inout_z LPWSTR* psczCommandLine,
26 - __in_z LPCWSTR wzArgument
27 - )
28 -{
29 - HRESULT hr = S_OK;
30 - LPWSTR sczQuotedArg = NULL;
31 - BOOL fRequiresQuoting = FALSE;
32 - DWORD dwMaxEscapedSize = 0;
33 -
34 - // Loop through the argument determining if it needs to be quoted and what the maximum
35 - // size would be if there are escape characters required.
36 - for (LPCWSTR pwz = wzArgument; *pwz; ++pwz)
37 - {
38 - // Arguments with whitespace need quoting.
39 - if (L' ' == *pwz || L'\t' == *pwz || L'\n' == *pwz || L'\v' == *pwz)
40 - {
41 - fRequiresQuoting = TRUE;
42 - }
43 - else if (L'"' == *pwz) // quotes need quoting and sometimes escaping.
44 - {
45 - fRequiresQuoting = TRUE;
46 - ++dwMaxEscapedSize;
47 - }
48 - else if (L'\\' == *pwz) // some backslashes need escaping, so we'll count them all to make sure there is room.
49 - {
50 - ++dwMaxEscapedSize;
51 - }
52 -
53 - ++dwMaxEscapedSize;
54 - }
55 -
56 - // If we found anything in the argument that requires our argument to be quoted
57 - if (fRequiresQuoting)
58 - {
59 - hr = StrAlloc(&sczQuotedArg, dwMaxEscapedSize + 3); // plus three for the start and end quote plus null terminator.
60 - PathExitOnFailure(hr, "Failed to allocate argument to be quoted.");
61 -
62 - LPCWSTR pwz = wzArgument;
63 - LPWSTR pwzQuoted = sczQuotedArg;
64 -
65 - *pwzQuoted = L'"';
66 - ++pwzQuoted;
67 - while (*pwz)
68 - {
69 - DWORD dwBackslashes = 0;
70 - while (L'\\' == *pwz)
71 - {
72 - ++dwBackslashes;
73 - ++pwz;
74 - }
75 -
76 - // Escape all backslashes at the end of the string.
77 - if (!*pwz)
78 - {
79 - dwBackslashes *= 2;
80 - }
81 - else if (L'"' == *pwz) // escape all backslashes before the quote and escape the quote itself.
82 - {
83 - dwBackslashes = dwBackslashes * 2 + 1;
84 - }
85 - // the backslashes don't have to be escaped.
86 -
87 - // Add the appropriate number of backslashes
88 - for (DWORD i = 0; i < dwBackslashes; ++i)
89 - {
90 - *pwzQuoted = L'\\';
91 - ++pwzQuoted;
92 - }
93 -
94 - // If there is a character, add it after all the escaped backslashes
95 - if (*pwz)
96 - {
97 - *pwzQuoted = *pwz;
98 - ++pwz;
99 - ++pwzQuoted;
100 - }
101 - }
102 -
103 - *pwzQuoted = L'"';
104 - ++pwzQuoted;
105 - *pwzQuoted = L'\0'; // ensure the arg is null terminated.
106 - }
107 -
108 - // If there is already data in the command line, append a space before appending the
109 - // argument.
110 - if (*psczCommandLine && **psczCommandLine)
111 - {
112 - hr = StrAllocConcat(psczCommandLine, L" ", 0);
113 - PathExitOnFailure(hr, "Failed to append space to command line with existing data.");
114 - }
115 -
116 - hr = StrAllocConcat(psczCommandLine, sczQuotedArg ? sczQuotedArg : wzArgument, 0);
117 - PathExitOnFailure(hr, "Failed to copy command line argument.");
118 -
119 -LExit:
120 - ReleaseStr(sczQuotedArg);
121 -
122 - return hr;
123 -}
124 -
125 -
24 DAPI_(LPWSTR) PathFile(
25 __in_z LPCWSTR wzPath
26 )
src/libs/dutil/WixToolset.DUtil/precomp.h
+1
@@ -45,6 +45,7 @@
45 #include "dutil.h"
46 #include "verutil.h"
47 #include "aclutil.h"
48 +#include "apputil.h"
49 #include "atomutil.h"
50 #include "buffutil.h"
51 #include "butil.h"