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"