aboutsummaryrefslogtreecommitdiff
path: root/src/engine/variable.cpp
diff options
context:
space:
mode:
authorSean Hall <r.sean.hall@gmail.com>2018-12-29 22:12:08 -0600
committerSean Hall <r.sean.hall@gmail.com>2018-12-29 22:12:08 -0600
commit61847dddd4fd497057c780658e383c4627de19ec (patch)
treef85a845182922538ab9aa6ee85b0db3ab40c1f6e /src/engine/variable.cpp
parent8295f5f8fd28042e1a0a172d5afbba79178064c2 (diff)
downloadwix-61847dddd4fd497057c780658e383c4627de19ec.tar.gz
wix-61847dddd4fd497057c780658e383c4627de19ec.tar.bz2
wix-61847dddd4fd497057c780658e383c4627de19ec.zip
Import code from old v4 repo
Diffstat (limited to 'src/engine/variable.cpp')
-rw-r--r--src/engine/variable.cpp2345
1 files changed, 2345 insertions, 0 deletions
diff --git a/src/engine/variable.cpp b/src/engine/variable.cpp
new file mode 100644
index 00000000..ed4abea2
--- /dev/null
+++ b/src/engine/variable.cpp
@@ -0,0 +1,2345 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6// structs
7
8typedef const struct _BUILT_IN_VARIABLE_DECLARATION
9{
10 LPCWSTR wzVariable;
11 PFN_INITIALIZEVARIABLE pfnInitialize;
12 DWORD_PTR dwpInitializeData;
13 BOOL fPersist;
14 BOOL fOverridable;
15} BUILT_IN_VARIABLE_DECLARATION;
16
17
18// constants
19
20const DWORD GROW_VARIABLE_ARRAY = 3;
21
22enum OS_INFO_VARIABLE
23{
24 OS_INFO_VARIABLE_NONE,
25 OS_INFO_VARIABLE_VersionNT,
26 OS_INFO_VARIABLE_VersionNT64,
27 OS_INFO_VARIABLE_ServicePackLevel,
28 OS_INFO_VARIABLE_NTProductType,
29 OS_INFO_VARIABLE_NTSuiteBackOffice,
30 OS_INFO_VARIABLE_NTSuiteDataCenter,
31 OS_INFO_VARIABLE_NTSuiteEnterprise,
32 OS_INFO_VARIABLE_NTSuitePersonal,
33 OS_INFO_VARIABLE_NTSuiteSmallBusiness,
34 OS_INFO_VARIABLE_NTSuiteSmallBusinessRestricted,
35 OS_INFO_VARIABLE_NTSuiteWebServer,
36 OS_INFO_VARIABLE_CompatibilityMode,
37 OS_INFO_VARIABLE_TerminalServer,
38 OS_INFO_VARIABLE_ProcessorArchitecture,
39};
40
41enum SET_VARIABLE
42{
43 SET_VARIABLE_NOT_BUILTIN,
44 SET_VARIABLE_OVERRIDE_BUILTIN,
45 SET_VARIABLE_OVERRIDE_PERSISTED_BUILTINS,
46 SET_VARIABLE_ANY,
47};
48
49// internal function declarations
50
51static HRESULT FormatString(
52 __in BURN_VARIABLES* pVariables,
53 __in_z LPCWSTR wzIn,
54 __out_z_opt LPWSTR* psczOut,
55 __out_opt DWORD* pcchOut,
56 __in BOOL fObfuscateHiddenVariables
57 );
58static HRESULT AddBuiltInVariable(
59 __in BURN_VARIABLES* pVariables,
60 __in LPCWSTR wzVariable,
61 __in PFN_INITIALIZEVARIABLE pfnInitialize,
62 __in DWORD_PTR dwpInitializeData,
63 __in BOOL fPersist,
64 __in BOOL fOverridable
65 );
66static HRESULT GetVariable(
67 __in BURN_VARIABLES* pVariables,
68 __in_z LPCWSTR wzVariable,
69 __out BURN_VARIABLE** ppVariable
70 );
71static HRESULT FindVariableIndexByName(
72 __in BURN_VARIABLES* pVariables,
73 __in_z LPCWSTR wzVariable,
74 __out DWORD* piVariable
75 );
76static HRESULT InsertVariable(
77 __in BURN_VARIABLES* pVariables,
78 __in_z LPCWSTR wzVariable,
79 __in DWORD iPosition
80 );
81static HRESULT SetVariableValue(
82 __in BURN_VARIABLES* pVariables,
83 __in_z LPCWSTR wzVariable,
84 __in BURN_VARIANT* pVariant,
85 __in BOOL fLiteral,
86 __in SET_VARIABLE setBuiltin,
87 __in BOOL fLog
88 );
89static HRESULT InitializeVariableVersionNT(
90 __in DWORD_PTR dwpData,
91 __inout BURN_VARIANT* pValue
92 );
93static HRESULT InitializeVariableOsInfo(
94 __in DWORD_PTR dwpData,
95 __inout BURN_VARIANT* pValue
96 );
97static HRESULT InitializeVariableSystemInfo(
98 __in DWORD_PTR dwpData,
99 __inout BURN_VARIANT* pValue
100 );
101static HRESULT InitializeVariableComputerName(
102 __in DWORD_PTR dwpData,
103 __inout BURN_VARIANT* pValue
104 );
105static HRESULT InitializeVariableVersionMsi(
106 __in DWORD_PTR dwpData,
107 __inout BURN_VARIANT* pValue
108 );
109static HRESULT InitializeVariableCsidlFolder(
110 __in DWORD_PTR dwpData,
111 __inout BURN_VARIANT* pValue
112 );
113static HRESULT InitializeVariableWindowsVolumeFolder(
114 __in DWORD_PTR dwpData,
115 __inout BURN_VARIANT* pValue
116 );
117static HRESULT InitializeVariableTempFolder(
118 __in DWORD_PTR dwpData,
119 __inout BURN_VARIANT* pValue
120 );
121static HRESULT InitializeVariableSystemFolder(
122 __in DWORD_PTR dwpData,
123 __inout BURN_VARIANT* pValue
124 );
125static HRESULT InitializeVariablePrivileged(
126 __in DWORD_PTR dwpData,
127 __inout BURN_VARIANT* pValue
128 );
129static HRESULT InitializeVariableRebootPending(
130 __in DWORD_PTR dwpData,
131 __inout BURN_VARIANT* pValue
132 );
133static HRESULT InitializeSystemLanguageID(
134 __in DWORD_PTR dwpData,
135 __inout BURN_VARIANT* pValue
136 );
137static HRESULT InitializeUserUILanguageID(
138 __in DWORD_PTR dwpData,
139 __inout BURN_VARIANT* pValue
140 );
141static HRESULT InitializeUserLanguageID(
142 __in DWORD_PTR dwpData,
143 __inout BURN_VARIANT* pValue
144 );
145static HRESULT InitializeVariableString(
146 __in DWORD_PTR dwpData,
147 __inout BURN_VARIANT* pValue
148 );
149static HRESULT InitializeVariableNumeric(
150 __in DWORD_PTR dwpData,
151 __inout BURN_VARIANT* pValue
152 );
153static HRESULT InitializeVariableRegistryFolder(
154 __in DWORD_PTR dwpData,
155 __inout BURN_VARIANT* pValue
156 );
157static HRESULT InitializeVariable6432Folder(
158 __in DWORD_PTR dwpData,
159 __inout BURN_VARIANT* pValue
160 );
161static HRESULT InitializeVariableDate(
162 __in DWORD_PTR dwpData,
163 __inout BURN_VARIANT* pValue
164 );
165static HRESULT InitializeVariableInstallerName(
166 __in DWORD_PTR dwpData,
167 __inout BURN_VARIANT* pValue
168 );
169static HRESULT InitializeVariableInstallerVersion(
170 __in DWORD_PTR dwpData,
171 __inout BURN_VARIANT* pValue
172 );
173static HRESULT InitializeVariableVersion(
174 __in DWORD_PTR dwpData,
175 __inout BURN_VARIANT* pValue
176 );
177static HRESULT InitializeVariableLogonUser(
178 __in DWORD_PTR dwpData,
179 __inout BURN_VARIANT* pValue
180 );
181static HRESULT Get64bitFolderFromRegistry(
182 __in int nFolder,
183 __deref_out_z LPWSTR* psczPath
184 );
185
186
187// function definitions
188
189extern "C" HRESULT VariableInitialize(
190 __in BURN_VARIABLES* pVariables
191 )
192{
193 HRESULT hr = S_OK;
194
195 ::InitializeCriticalSection(&pVariables->csAccess);
196
197 const BUILT_IN_VARIABLE_DECLARATION vrgBuiltInVariables[] = {
198 {L"AdminToolsFolder", InitializeVariableCsidlFolder, CSIDL_ADMINTOOLS},
199 {L"AppDataFolder", InitializeVariableCsidlFolder, CSIDL_APPDATA},
200 {L"CommonAppDataFolder", InitializeVariableCsidlFolder, CSIDL_COMMON_APPDATA},
201#if defined(_WIN64)
202 {L"CommonFiles64Folder", InitializeVariableCsidlFolder, CSIDL_PROGRAM_FILES_COMMON},
203 {L"CommonFilesFolder", InitializeVariableCsidlFolder, CSIDL_PROGRAM_FILES_COMMONX86},
204#else
205 {L"CommonFiles64Folder", InitializeVariableRegistryFolder, CSIDL_PROGRAM_FILES_COMMON},
206 {L"CommonFilesFolder", InitializeVariableCsidlFolder, CSIDL_PROGRAM_FILES_COMMON},
207#endif
208 {L"CommonFiles6432Folder", InitializeVariable6432Folder, CSIDL_PROGRAM_FILES_COMMON},
209 {L"CompatibilityMode", InitializeVariableOsInfo, OS_INFO_VARIABLE_CompatibilityMode},
210 {VARIABLE_DATE, InitializeVariableDate, 0},
211 {L"ComputerName", InitializeVariableComputerName, 0},
212 {L"DesktopFolder", InitializeVariableCsidlFolder, CSIDL_DESKTOP},
213 {L"FavoritesFolder", InitializeVariableCsidlFolder, CSIDL_FAVORITES},
214 {L"FontsFolder", InitializeVariableCsidlFolder, CSIDL_FONTS},
215 {VARIABLE_INSTALLERNAME, InitializeVariableInstallerName, 0},
216 {VARIABLE_INSTALLERVERSION, InitializeVariableInstallerVersion, 0},
217 {L"LocalAppDataFolder", InitializeVariableCsidlFolder, CSIDL_LOCAL_APPDATA},
218 {VARIABLE_LOGONUSER, InitializeVariableLogonUser, 0},
219 {L"MyPicturesFolder", InitializeVariableCsidlFolder, CSIDL_MYPICTURES},
220 {L"NTProductType", InitializeVariableOsInfo, OS_INFO_VARIABLE_NTProductType},
221 {L"NTSuiteBackOffice", InitializeVariableOsInfo, OS_INFO_VARIABLE_NTSuiteBackOffice},
222 {L"NTSuiteDataCenter", InitializeVariableOsInfo, OS_INFO_VARIABLE_NTSuiteDataCenter},
223 {L"NTSuiteEnterprise", InitializeVariableOsInfo, OS_INFO_VARIABLE_NTSuiteEnterprise},
224 {L"NTSuitePersonal", InitializeVariableOsInfo, OS_INFO_VARIABLE_NTSuitePersonal},
225 {L"NTSuiteSmallBusiness", InitializeVariableOsInfo, OS_INFO_VARIABLE_NTSuiteSmallBusiness},
226 {L"NTSuiteSmallBusinessRestricted", InitializeVariableOsInfo, OS_INFO_VARIABLE_NTSuiteSmallBusinessRestricted},
227 {L"NTSuiteWebServer", InitializeVariableOsInfo, OS_INFO_VARIABLE_NTSuiteWebServer},
228 {L"PersonalFolder", InitializeVariableCsidlFolder, CSIDL_PERSONAL},
229 {L"Privileged", InitializeVariablePrivileged, 0},
230 {L"ProcessorArchitecture", InitializeVariableSystemInfo, OS_INFO_VARIABLE_ProcessorArchitecture},
231#if defined(_WIN64)
232 {L"ProgramFiles64Folder", InitializeVariableCsidlFolder, CSIDL_PROGRAM_FILES},
233 {L"ProgramFilesFolder", InitializeVariableCsidlFolder, CSIDL_PROGRAM_FILESX86},
234#else
235 {L"ProgramFiles64Folder", InitializeVariableRegistryFolder, CSIDL_PROGRAM_FILES},
236 {L"ProgramFilesFolder", InitializeVariableCsidlFolder, CSIDL_PROGRAM_FILES},
237#endif
238 {L"ProgramFiles6432Folder", InitializeVariable6432Folder, CSIDL_PROGRAM_FILES},
239 {L"ProgramMenuFolder", InitializeVariableCsidlFolder, CSIDL_PROGRAMS},
240 {L"RebootPending", InitializeVariableRebootPending, 0},
241 {L"SendToFolder", InitializeVariableCsidlFolder, CSIDL_SENDTO},
242 {L"ServicePackLevel", InitializeVariableVersionNT, OS_INFO_VARIABLE_ServicePackLevel},
243 {L"StartMenuFolder", InitializeVariableCsidlFolder, CSIDL_STARTMENU},
244 {L"StartupFolder", InitializeVariableCsidlFolder, CSIDL_STARTUP},
245 {L"SystemFolder", InitializeVariableSystemFolder, FALSE},
246 {L"System64Folder", InitializeVariableSystemFolder, TRUE},
247 {L"SystemLanguageID", InitializeSystemLanguageID, 0},
248 {L"TempFolder", InitializeVariableTempFolder, 0},
249 {L"TemplateFolder", InitializeVariableCsidlFolder, CSIDL_TEMPLATES},
250 {L"TerminalServer", InitializeVariableOsInfo, OS_INFO_VARIABLE_TerminalServer},
251 {L"UserUILanguageID", InitializeUserUILanguageID, 0},
252 {L"UserLanguageID", InitializeUserLanguageID, 0},
253 {L"VersionMsi", InitializeVariableVersionMsi, 0},
254 {L"VersionNT", InitializeVariableVersionNT, OS_INFO_VARIABLE_VersionNT},
255 {L"VersionNT64", InitializeVariableVersionNT, OS_INFO_VARIABLE_VersionNT64},
256 {L"WindowsFolder", InitializeVariableCsidlFolder, CSIDL_WINDOWS},
257 {L"WindowsVolume", InitializeVariableWindowsVolumeFolder, 0},
258 {BURN_BUNDLE_ACTION, InitializeVariableNumeric, 0, FALSE, TRUE},
259 {BURN_BUNDLE_EXECUTE_PACKAGE_CACHE_FOLDER, InitializeVariableString, NULL, FALSE, TRUE},
260 {BURN_BUNDLE_EXECUTE_PACKAGE_ACTION, InitializeVariableString, NULL, FALSE, TRUE},
261 {BURN_BUNDLE_FORCED_RESTART_PACKAGE, InitializeVariableString, NULL, TRUE, TRUE},
262 {BURN_BUNDLE_INSTALLED, InitializeVariableNumeric, 0, FALSE, TRUE},
263 {BURN_BUNDLE_ELEVATED, InitializeVariableNumeric, 0, FALSE, TRUE},
264 {BURN_BUNDLE_ACTIVE_PARENT, InitializeVariableString, NULL, FALSE, TRUE},
265 {BURN_BUNDLE_PROVIDER_KEY, InitializeVariableString, (DWORD_PTR)L"", FALSE, TRUE},
266 {BURN_BUNDLE_SOURCE_PROCESS_PATH, InitializeVariableString, NULL, FALSE, TRUE},
267 {BURN_BUNDLE_SOURCE_PROCESS_FOLDER, InitializeVariableString, NULL, FALSE, TRUE},
268 {BURN_BUNDLE_TAG, InitializeVariableString, (DWORD_PTR)L"", FALSE, TRUE},
269 {BURN_BUNDLE_UILEVEL, InitializeVariableNumeric, 0, FALSE, TRUE},
270 {BURN_BUNDLE_VERSION, InitializeVariableVersion, 0, FALSE, TRUE},
271 };
272
273 for (DWORD i = 0; i < countof(vrgBuiltInVariables); ++i)
274 {
275 BUILT_IN_VARIABLE_DECLARATION* pBuiltInVariable = &vrgBuiltInVariables[i];
276
277 hr = AddBuiltInVariable(pVariables, pBuiltInVariable->wzVariable, pBuiltInVariable->pfnInitialize, pBuiltInVariable->dwpInitializeData, pBuiltInVariable->fPersist, pBuiltInVariable->fOverridable);
278 ExitOnFailure(hr, "Failed to add built-in variable: %ls.", pBuiltInVariable->wzVariable);
279 }
280
281LExit:
282 return hr;
283}
284
285extern "C" HRESULT VariablesParseFromXml(
286 __in BURN_VARIABLES* pVariables,
287 __in IXMLDOMNode* pixnBundle
288 )
289{
290 HRESULT hr = S_OK;
291 IXMLDOMNodeList* pixnNodes = NULL;
292 IXMLDOMNode* pixnNode = NULL;
293 DWORD cNodes = 0;
294 LPWSTR sczId = NULL;
295 LPWSTR scz = NULL;
296 BURN_VARIANT value = { };
297 BURN_VARIANT_TYPE valueType = BURN_VARIANT_TYPE_NONE;
298 BOOL fHidden = FALSE;
299 BOOL fPersisted = FALSE;
300 DWORD iVariable = 0;
301
302 ::EnterCriticalSection(&pVariables->csAccess);
303
304 // select variable nodes
305 hr = XmlSelectNodes(pixnBundle, L"Variable", &pixnNodes);
306 ExitOnFailure(hr, "Failed to select variable nodes.");
307
308 // get variable node count
309 hr = pixnNodes->get_length((long*)&cNodes);
310 ExitOnFailure(hr, "Failed to get variable node count.");
311
312 // parse package elements
313 for (DWORD i = 0; i < cNodes; ++i)
314 {
315 hr = XmlNextElement(pixnNodes, &pixnNode, NULL);
316 ExitOnFailure(hr, "Failed to get next node.");
317
318 // @Id
319 hr = XmlGetAttributeEx(pixnNode, L"Id", &sczId);
320 ExitOnFailure(hr, "Failed to get @Id.");
321
322 // @Hidden
323 hr = XmlGetYesNoAttribute(pixnNode, L"Hidden", &fHidden);
324 ExitOnFailure(hr, "Failed to get @Hidden.");
325
326 // @Persisted
327 hr = XmlGetYesNoAttribute(pixnNode, L"Persisted", &fPersisted);
328 ExitOnFailure(hr, "Failed to get @Persisted.");
329
330 // @Value
331 hr = XmlGetAttributeEx(pixnNode, L"Value", &scz);
332 if (E_NOTFOUND != hr)
333 {
334 ExitOnFailure(hr, "Failed to get @Value.");
335
336 hr = BVariantSetString(&value, scz, 0);
337 ExitOnFailure(hr, "Failed to set variant value.");
338
339 // @Type
340 hr = XmlGetAttributeEx(pixnNode, L"Type", &scz);
341 ExitOnFailure(hr, "Failed to get @Type.");
342
343 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"numeric", -1))
344 {
345 if (!fHidden)
346 {
347 LogStringLine(REPORT_STANDARD, "Initializing numeric variable '%ls' to value '%ls'", sczId, value.sczValue);
348 }
349 valueType = BURN_VARIANT_TYPE_NUMERIC;
350 }
351 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"string", -1))
352 {
353 if (!fHidden)
354 {
355 LogStringLine(REPORT_STANDARD, "Initializing string variable '%ls' to value '%ls'", sczId, value.sczValue);
356 }
357 valueType = BURN_VARIANT_TYPE_STRING;
358 }
359 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"version", -1))
360 {
361 if (!fHidden)
362 {
363 LogStringLine(REPORT_STANDARD, "Initializing version variable '%ls' to value '%ls'", sczId, value.sczValue);
364 }
365 valueType = BURN_VARIANT_TYPE_VERSION;
366 }
367 else
368 {
369 hr = E_INVALIDARG;
370 ExitOnFailure(hr, "Invalid value for @Type: %ls", scz);
371 }
372 }
373 else
374 {
375 valueType = BURN_VARIANT_TYPE_NONE;
376 }
377
378 if (fHidden)
379 {
380 LogStringLine(REPORT_STANDARD, "Initializing hidden variable '%ls'", sczId);
381 }
382
383 // change value variant to correct type
384 hr = BVariantChangeType(&value, valueType);
385 ExitOnFailure(hr, "Failed to change variant type.");
386
387 // find existing variable
388 hr = FindVariableIndexByName(pVariables, sczId, &iVariable);
389 ExitOnFailure(hr, "Failed to find variable value '%ls'.", sczId);
390
391 // insert element if not found
392 if (S_FALSE == hr)
393 {
394 hr = InsertVariable(pVariables, sczId, iVariable);
395 ExitOnFailure(hr, "Failed to insert variable '%ls'.", sczId);
396 }
397 else if (BURN_VARIABLE_INTERNAL_TYPE_NORMAL < pVariables->rgVariables[iVariable].internalType)
398 {
399 hr = E_INVALIDARG;
400 ExitOnRootFailure(hr, "Attempt to set built-in variable value: %ls", sczId);
401 }
402 pVariables->rgVariables[iVariable].fHidden = fHidden;
403 pVariables->rgVariables[iVariable].fPersisted = fPersisted;
404
405 // update variable value
406 hr = BVariantSetValue(&pVariables->rgVariables[iVariable].Value, &value);
407 ExitOnFailure(hr, "Failed to set value of variable: %ls", sczId);
408
409 hr = BVariantSetEncryption(&pVariables->rgVariables[iVariable].Value, fHidden);
410 ExitOnFailure(hr, "Failed to set variant encryption");
411
412 // prepare next iteration
413 ReleaseNullObject(pixnNode);
414 BVariantUninitialize(&value);
415 ReleaseNullStrSecure(scz);
416 }
417
418LExit:
419 ::LeaveCriticalSection(&pVariables->csAccess);
420
421 ReleaseObject(pixnNodes);
422 ReleaseObject(pixnNode);
423 ReleaseStr(scz);
424 ReleaseStr(sczId);
425 BVariantUninitialize(&value);
426
427 return hr;
428}
429
430extern "C" void VariablesUninitialize(
431 __in BURN_VARIABLES* pVariables
432 )
433{
434 ::DeleteCriticalSection(&pVariables->csAccess);
435
436 if (pVariables->rgVariables)
437 {
438 for (DWORD i = 0; i < pVariables->cVariables; ++i)
439 {
440 BURN_VARIABLE* pVariable = &pVariables->rgVariables[i];
441 if (pVariable)
442 {
443 ReleaseStr(pVariable->sczName);
444 BVariantUninitialize(&pVariable->Value);
445 }
446 }
447 MemFree(pVariables->rgVariables);
448 }
449}
450
451extern "C" void VariablesDump(
452 __in BURN_VARIABLES* pVariables
453 )
454{
455 HRESULT hr = S_OK;
456 LPWSTR sczValue = NULL;
457
458 for (DWORD i = 0; i < pVariables->cVariables; ++i)
459 {
460 BURN_VARIABLE* pVariable = &pVariables->rgVariables[i];
461 if (pVariable && BURN_VARIANT_TYPE_NONE != pVariable->Value.Type)
462 {
463 hr = StrAllocFormatted(&sczValue, L"%ls = [%ls]", pVariable->sczName, pVariable->sczName);
464 if (SUCCEEDED(hr))
465 {
466 if (pVariable->fHidden)
467 {
468 hr = VariableFormatStringObfuscated(pVariables, sczValue, &sczValue, NULL);
469 }
470 else
471 {
472 hr = VariableFormatString(pVariables, sczValue, &sczValue, NULL);
473 }
474 }
475
476 if (FAILED(hr))
477 {
478 // already logged; best-effort to dump the rest on our way out the door
479 continue;
480 }
481
482 LogId(REPORT_VERBOSE, MSG_VARIABLE_DUMP, sczValue);
483
484 ReleaseNullStrSecure(sczValue);
485 }
486 }
487
488 StrSecureZeroFreeString(sczValue);
489}
490
491// The contents of pllValue may be sensitive, if variable is hidden should keep value encrypted and SecureZeroMemory.
492extern "C" HRESULT VariableGetNumeric(
493 __in BURN_VARIABLES* pVariables,
494 __in_z LPCWSTR wzVariable,
495 __out LONGLONG* pllValue
496 )
497{
498 HRESULT hr = S_OK;
499 BURN_VARIABLE* pVariable = NULL;
500
501 ::EnterCriticalSection(&pVariables->csAccess);
502
503 hr = GetVariable(pVariables, wzVariable, &pVariable);
504 if (SUCCEEDED(hr) && BURN_VARIANT_TYPE_NONE == pVariable->Value.Type)
505 {
506 ExitFunction1(hr = E_NOTFOUND);
507 }
508 else if (E_NOTFOUND == hr)
509 {
510 ExitFunction();
511 }
512 ExitOnFailure(hr, "Failed to get value of variable: %ls", wzVariable);
513
514 hr = BVariantGetNumeric(&pVariable->Value, pllValue);
515 ExitOnFailure(hr, "Failed to get value as numeric for variable: %ls", wzVariable);
516
517LExit:
518 ::LeaveCriticalSection(&pVariables->csAccess);
519
520 return hr;
521}
522
523// The contents of psczValue may be sensitive, if variable is hidden should keep encrypted and SecureZeroFree.
524extern "C" HRESULT VariableGetString(
525 __in BURN_VARIABLES* pVariables,
526 __in_z LPCWSTR wzVariable,
527 __out_z LPWSTR* psczValue
528 )
529{
530 HRESULT hr = S_OK;
531 BURN_VARIABLE* pVariable = NULL;
532
533 ::EnterCriticalSection(&pVariables->csAccess);
534
535 hr = GetVariable(pVariables, wzVariable, &pVariable);
536 if (SUCCEEDED(hr) && BURN_VARIANT_TYPE_NONE == pVariable->Value.Type)
537 {
538 ExitFunction1(hr = E_NOTFOUND);
539 }
540 else if (E_NOTFOUND == hr)
541 {
542 ExitFunction();
543 }
544 ExitOnFailure(hr, "Failed to get value of variable: %ls", wzVariable);
545
546 hr = BVariantGetString(&pVariable->Value, psczValue);
547 ExitOnFailure(hr, "Failed to get value as string for variable: %ls", wzVariable);
548
549LExit:
550 ::LeaveCriticalSection(&pVariables->csAccess);
551
552 return hr;
553}
554
555// The contents of pqwValue may be sensitive, if variable is hidden should keep value encrypted and SecureZeroMemory.
556extern "C" HRESULT VariableGetVersion(
557 __in BURN_VARIABLES* pVariables,
558 __in_z LPCWSTR wzVariable,
559 __in DWORD64* pqwValue
560 )
561{
562 HRESULT hr = S_OK;
563 BURN_VARIABLE* pVariable = NULL;
564
565 ::EnterCriticalSection(&pVariables->csAccess);
566
567 hr = GetVariable(pVariables, wzVariable, &pVariable);
568 if (SUCCEEDED(hr) && BURN_VARIANT_TYPE_NONE == pVariable->Value.Type)
569 {
570 ExitFunction1(hr = E_NOTFOUND);
571 }
572 else if (E_NOTFOUND == hr)
573 {
574 ExitFunction();
575 }
576 ExitOnFailure(hr, "Failed to get value of variable: %ls", wzVariable);
577
578 hr = BVariantGetVersion(&pVariable->Value, pqwValue);
579 ExitOnFailure(hr, "Failed to get value as version for variable: %ls", wzVariable);
580
581LExit:
582 ::LeaveCriticalSection(&pVariables->csAccess);
583
584 return hr;
585}
586
587extern "C" HRESULT VariableGetVariant(
588 __in BURN_VARIABLES* pVariables,
589 __in_z LPCWSTR wzVariable,
590 __in BURN_VARIANT* pValue
591 )
592{
593 HRESULT hr = S_OK;
594 BURN_VARIABLE* pVariable = NULL;
595
596 ::EnterCriticalSection(&pVariables->csAccess);
597
598 hr = GetVariable(pVariables, wzVariable, &pVariable);
599 if (E_NOTFOUND == hr)
600 {
601 ExitFunction();
602 }
603 ExitOnFailure(hr, "Failed to get value of variable: %ls", wzVariable);
604
605 hr = BVariantCopy(&pVariable->Value, pValue);
606 ExitOnFailure(hr, "Failed to copy value of variable: %ls", wzVariable);
607
608LExit:
609 ::LeaveCriticalSection(&pVariables->csAccess);
610
611 return hr;
612}
613
614// The contents of psczValue may be sensitive, should keep encrypted and SecureZeroFree.
615extern "C" HRESULT VariableGetFormatted(
616 __in BURN_VARIABLES* pVariables,
617 __in_z LPCWSTR wzVariable,
618 __out_z LPWSTR* psczValue
619 )
620{
621 HRESULT hr = S_OK;
622 BURN_VARIABLE* pVariable = NULL;
623 LPWSTR scz = NULL;
624
625 ::EnterCriticalSection(&pVariables->csAccess);
626
627 hr = GetVariable(pVariables, wzVariable, &pVariable);
628 if (SUCCEEDED(hr) && BURN_VARIANT_TYPE_NONE == pVariable->Value.Type)
629 {
630 ExitFunction1(hr = E_NOTFOUND);
631 }
632 else if (E_NOTFOUND == hr)
633 {
634 ExitFunction();
635 }
636 ExitOnFailure(hr, "Failed to get variable: %ls", wzVariable);
637
638 // Strings need to get expanded unless they're built-in or literal because they're guaranteed not to have embedded variables.
639 if (BURN_VARIANT_TYPE_STRING == pVariable->Value.Type &&
640 BURN_VARIABLE_INTERNAL_TYPE_NORMAL == pVariable->internalType &&
641 !pVariable->fLiteral)
642 {
643 hr = BVariantGetString(&pVariable->Value, &scz);
644 ExitOnFailure(hr, "Failed to get unformatted string.");
645
646 hr = VariableFormatString(pVariables, scz, psczValue, NULL);
647 ExitOnFailure(hr, "Failed to format value '%ls' of variable: %ls", pVariable->fHidden ? L"*****" : pVariable->Value.sczValue, wzVariable);
648 }
649 else
650 {
651 hr = BVariantGetString(&pVariable->Value, psczValue);
652 ExitOnFailure(hr, "Failed to get value as string for variable: %ls", wzVariable);
653 }
654
655LExit:
656 ::LeaveCriticalSection(&pVariables->csAccess);
657 StrSecureZeroFreeString(scz);
658
659 return hr;
660}
661
662extern "C" HRESULT VariableSetNumeric(
663 __in BURN_VARIABLES* pVariables,
664 __in_z LPCWSTR wzVariable,
665 __in LONGLONG llValue,
666 __in BOOL fOverwriteBuiltIn
667 )
668{
669 BURN_VARIANT variant = { };
670
671 // We're not going to encrypt this value, so can access the value directly.
672 variant.llValue = llValue;
673 variant.Type = BURN_VARIANT_TYPE_NUMERIC;
674
675 return SetVariableValue(pVariables, wzVariable, &variant, FALSE, fOverwriteBuiltIn ? SET_VARIABLE_OVERRIDE_BUILTIN : SET_VARIABLE_NOT_BUILTIN, TRUE);
676}
677
678extern "C" HRESULT VariableSetLiteralString(
679 __in BURN_VARIABLES* pVariables,
680 __in_z LPCWSTR wzVariable,
681 __in_z_opt LPCWSTR wzValue,
682 __in BOOL fOverwriteBuiltIn
683 )
684{
685 BURN_VARIANT variant = { };
686
687 // We're not going to encrypt this value, so can access the value directly.
688 variant.sczValue = (LPWSTR)wzValue;
689 variant.Type = BURN_VARIANT_TYPE_STRING;
690
691 return SetVariableValue(pVariables, wzVariable, &variant, TRUE, fOverwriteBuiltIn ? SET_VARIABLE_OVERRIDE_BUILTIN : SET_VARIABLE_NOT_BUILTIN, TRUE);
692}
693
694extern "C" HRESULT VariableSetString(
695 __in BURN_VARIABLES* pVariables,
696 __in_z LPCWSTR wzVariable,
697 __in_z_opt LPCWSTR wzValue,
698 __in BOOL fOverwriteBuiltIn
699 )
700{
701 BURN_VARIANT variant = { };
702
703 // We're not going to encrypt this value, so can access the value directly.
704 variant.sczValue = (LPWSTR)wzValue;
705 variant.Type = BURN_VARIANT_TYPE_STRING;
706
707 return SetVariableValue(pVariables, wzVariable, &variant, FALSE, fOverwriteBuiltIn ? SET_VARIABLE_OVERRIDE_BUILTIN : SET_VARIABLE_NOT_BUILTIN, TRUE);
708}
709
710extern "C" HRESULT VariableSetVersion(
711 __in BURN_VARIABLES* pVariables,
712 __in_z LPCWSTR wzVariable,
713 __in DWORD64 qwValue,
714 __in BOOL fOverwriteBuiltIn
715 )
716{
717 BURN_VARIANT variant = { };
718
719 // We're not going to encrypt this value, so can access the value directly.
720 variant.qwValue = qwValue;
721 variant.Type = BURN_VARIANT_TYPE_VERSION;
722
723 return SetVariableValue(pVariables, wzVariable, &variant, FALSE, fOverwriteBuiltIn ? SET_VARIABLE_OVERRIDE_BUILTIN : SET_VARIABLE_NOT_BUILTIN, TRUE);
724}
725
726extern "C" HRESULT VariableSetLiteralVariant(
727 __in BURN_VARIABLES* pVariables,
728 __in_z LPCWSTR wzVariable,
729 __in BURN_VARIANT* pVariant
730 )
731{
732 return SetVariableValue(pVariables, wzVariable, pVariant, TRUE, SET_VARIABLE_NOT_BUILTIN, TRUE);
733}
734
735// The contents of psczOut may be sensitive, should keep encrypted and SecureZeroFree
736extern "C" HRESULT VariableFormatString(
737 __in BURN_VARIABLES* pVariables,
738 __in_z LPCWSTR wzIn,
739 __out_z_opt LPWSTR* psczOut,
740 __out_opt DWORD* pcchOut
741 )
742{
743 return FormatString(pVariables, wzIn, psczOut, pcchOut, FALSE);
744}
745
746extern "C" HRESULT VariableFormatStringObfuscated(
747 __in BURN_VARIABLES* pVariables,
748 __in_z LPCWSTR wzIn,
749 __out_z_opt LPWSTR* psczOut,
750 __out_opt DWORD* pcchOut
751 )
752{
753 return FormatString(pVariables, wzIn, psczOut, pcchOut, TRUE);
754}
755
756extern "C" HRESULT VariableEscapeString(
757 __in_z LPCWSTR wzIn,
758 __out_z LPWSTR* psczOut
759 )
760{
761 HRESULT hr = S_OK;
762 LPCWSTR wzRead = NULL;
763 LPWSTR pwzEscaped = NULL;
764 LPWSTR pwz = NULL;
765 SIZE_T i = 0;
766
767 // allocate buffer for escaped string
768 hr = StrAlloc(&pwzEscaped, lstrlenW(wzIn) + 1);
769 ExitOnFailure(hr, "Failed to allocate buffer for escaped string.");
770
771 // read through string and move characters, inserting escapes as needed
772 wzRead = wzIn;
773 for (;;)
774 {
775 // find next character needing escaping
776 i = wcscspn(wzRead, L"[]{}");
777
778 // copy skipped characters
779 if (0 < i)
780 {
781 hr = StrAllocConcat(&pwzEscaped, wzRead, i);
782 ExitOnFailure(hr, "Failed to append characters.");
783 }
784
785 if (L'\0' == wzRead[i])
786 {
787 break; // end reached
788 }
789
790 // escape character
791 hr = StrAllocFormatted(&pwz, L"[\\%c]", wzRead[i]);
792 ExitOnFailure(hr, "Failed to format escape sequence.");
793
794 hr = StrAllocConcat(&pwzEscaped, pwz, 0);
795 ExitOnFailure(hr, "Failed to append escape sequence.");
796
797 // update read pointer
798 wzRead += i + 1;
799 }
800
801 // return value
802 hr = StrAllocString(psczOut, pwzEscaped, 0);
803 ExitOnFailure(hr, "Failed to copy string.");
804
805LExit:
806 ReleaseStr(pwzEscaped);
807 ReleaseStr(pwz);
808 return hr;
809}
810
811extern "C" HRESULT VariableSerialize(
812 __in BURN_VARIABLES* pVariables,
813 __in BOOL fPersisting,
814 __inout BYTE** ppbBuffer,
815 __inout SIZE_T* piBuffer
816 )
817{
818 HRESULT hr = S_OK;
819 BOOL fIncluded = FALSE;
820 LONGLONG ll = 0;
821 LPWSTR scz = NULL;
822 DWORD64 qw = 0;
823
824 ::EnterCriticalSection(&pVariables->csAccess);
825
826 // Write variable count.
827 hr = BuffWriteNumber(ppbBuffer, piBuffer, pVariables->cVariables);
828 ExitOnFailure(hr, "Failed to write variable count.");
829
830 // Write variables.
831 for (DWORD i = 0; i < pVariables->cVariables; ++i)
832 {
833 BURN_VARIABLE* pVariable = &pVariables->rgVariables[i];
834
835 // If we aren't persisting, include only variables that aren't rejected by the elevated process.
836 // If we are persisting, include only variables that should be persisted.
837 fIncluded = (!fPersisting && BURN_VARIABLE_INTERNAL_TYPE_BUILTIN != pVariable->internalType) ||
838 (fPersisting && pVariable->fPersisted);
839
840 // Write included flag.
841 hr = BuffWriteNumber(ppbBuffer, piBuffer, (DWORD)fIncluded);
842 ExitOnFailure(hr, "Failed to write included flag.");
843
844 if (!fIncluded)
845 {
846 continue;
847 }
848
849 // Write variable name.
850 hr = BuffWriteString(ppbBuffer, piBuffer, pVariable->sczName);
851 ExitOnFailure(hr, "Failed to write variable name.");
852
853 // Write variable value type.
854 hr = BuffWriteNumber(ppbBuffer, piBuffer, (DWORD)pVariable->Value.Type);
855 ExitOnFailure(hr, "Failed to write variable value type.");
856
857 // Write variable value.
858 switch (pVariable->Value.Type)
859 {
860 case BURN_VARIANT_TYPE_NONE:
861 break;
862 case BURN_VARIANT_TYPE_NUMERIC:
863 hr = BVariantGetNumeric(&pVariable->Value, &ll);
864 ExitOnFailure(hr, "Failed to get numeric.");
865
866 hr = BuffWriteNumber64(ppbBuffer, piBuffer, static_cast<DWORD64>(ll));
867 ExitOnFailure(hr, "Failed to write variable value as number.");
868
869 SecureZeroMemory(&ll, sizeof(ll));
870 break;
871 case BURN_VARIANT_TYPE_VERSION:
872 hr = BVariantGetVersion(&pVariable->Value, &qw);
873 ExitOnFailure(hr, "Failed to get version.");
874
875 hr = BuffWriteNumber64(ppbBuffer, piBuffer, qw);
876 ExitOnFailure(hr, "Failed to write variable value as number.");
877
878 SecureZeroMemory(&qw, sizeof(qw));
879 break;
880 case BURN_VARIANT_TYPE_STRING:
881 hr = BVariantGetString(&pVariable->Value, &scz);
882 ExitOnFailure(hr, "Failed to get string.");
883
884 hr = BuffWriteString(ppbBuffer, piBuffer, scz);
885 ExitOnFailure(hr, "Failed to write variable value as string.");
886
887 ReleaseNullStrSecure(scz);
888 break;
889 default:
890 hr = E_INVALIDARG;
891 ExitOnFailure(hr, "Unsupported variable type.");
892 }
893
894 // Write literal flag.
895 hr = BuffWriteNumber(ppbBuffer, piBuffer, (DWORD)pVariable->fLiteral);
896 ExitOnFailure(hr, "Failed to write literal flag.");
897 }
898
899LExit:
900 ::LeaveCriticalSection(&pVariables->csAccess);
901 SecureZeroMemory(&ll, sizeof(ll));
902 SecureZeroMemory(&qw, sizeof(qw));
903 StrSecureZeroFreeString(scz);
904
905 return hr;
906}
907
908extern "C" HRESULT VariableDeserialize(
909 __in BURN_VARIABLES* pVariables,
910 __in BOOL fWasPersisted,
911 __in_bcount(cbBuffer) BYTE* pbBuffer,
912 __in SIZE_T cbBuffer,
913 __inout SIZE_T* piBuffer
914 )
915{
916 HRESULT hr = S_OK;
917 DWORD cVariables = 0;
918 LPWSTR sczName = NULL;
919 BOOL fIncluded = FALSE;
920 BOOL fLiteral = FALSE;
921 BURN_VARIANT value = { };
922 LPWSTR scz = NULL;
923 DWORD64 qw = 0;
924
925 ::EnterCriticalSection(&pVariables->csAccess);
926
927 // Read variable count.
928 hr = BuffReadNumber(pbBuffer, cbBuffer, piBuffer, &cVariables);
929 ExitOnFailure(hr, "Failed to read variable count.");
930
931 // Read variables.
932 for (DWORD i = 0; i < cVariables; ++i)
933 {
934 // Read variable included flag.
935 hr = BuffReadNumber(pbBuffer, cbBuffer, piBuffer, (DWORD*)&fIncluded);
936 ExitOnFailure(hr, "Failed to read variable included flag.");
937
938 if (!fIncluded)
939 {
940 continue; // if variable is not included, skip.
941 }
942
943 // Read variable name.
944 hr = BuffReadString(pbBuffer, cbBuffer, piBuffer, &sczName);
945 ExitOnFailure(hr, "Failed to read variable name.");
946
947 // Read variable value type.
948 hr = BuffReadNumber(pbBuffer, cbBuffer, piBuffer, (DWORD*)&value.Type);
949 ExitOnFailure(hr, "Failed to read variable value type.");
950
951 // Read variable value.
952 switch (value.Type)
953 {
954 case BURN_VARIANT_TYPE_NONE:
955 break;
956 case BURN_VARIANT_TYPE_NUMERIC:
957 hr = BuffReadNumber64(pbBuffer, cbBuffer, piBuffer, &qw);
958 ExitOnFailure(hr, "Failed to read variable value as number.");
959
960 hr = BVariantSetNumeric(&value, static_cast<LONGLONG>(qw));
961 ExitOnFailure(hr, "Failed to set variable value.");
962
963 SecureZeroMemory(&qw, sizeof(qw));
964 break;
965 case BURN_VARIANT_TYPE_VERSION:
966 hr = BuffReadNumber64(pbBuffer, cbBuffer, piBuffer, &qw);
967 ExitOnFailure(hr, "Failed to read variable value as number.");
968
969 hr = BVariantSetVersion(&value, qw);
970 ExitOnFailure(hr, "Failed to set variable value.");
971
972 SecureZeroMemory(&qw, sizeof(qw));
973 break;
974 case BURN_VARIANT_TYPE_STRING:
975 hr = BuffReadString(pbBuffer, cbBuffer, piBuffer, &scz);
976 ExitOnFailure(hr, "Failed to read variable value as string.");
977
978 hr = BVariantSetString(&value, scz, NULL);
979 ExitOnFailure(hr, "Failed to set variable value.");
980
981 ReleaseNullStrSecure(scz);
982 break;
983 default:
984 hr = E_INVALIDARG;
985 ExitOnFailure(hr, "Unsupported variable type.");
986 }
987
988 // Read variable literal flag.
989 hr = BuffReadNumber(pbBuffer, cbBuffer, piBuffer, (DWORD*)&fLiteral);
990 ExitOnFailure(hr, "Failed to read variable literal flag.");
991
992 // Set variable.
993 hr = SetVariableValue(pVariables, sczName, &value, fLiteral, fWasPersisted ? SET_VARIABLE_OVERRIDE_PERSISTED_BUILTINS : SET_VARIABLE_ANY, FALSE);
994 ExitOnFailure(hr, "Failed to set variable.");
995
996 // Clean up.
997 BVariantUninitialize(&value);
998 }
999
1000LExit:
1001 ::LeaveCriticalSection(&pVariables->csAccess);
1002
1003 ReleaseStr(sczName);
1004 BVariantUninitialize(&value);
1005 SecureZeroMemory(&qw, sizeof(qw));
1006 StrSecureZeroFreeString(scz);
1007
1008 return hr;
1009}
1010
1011extern "C" HRESULT VariableStrAlloc(
1012 __in BOOL fZeroOnRealloc,
1013 __deref_out_ecount_part(cch, 0) LPWSTR* ppwz,
1014 __in DWORD_PTR cch
1015 )
1016{
1017 HRESULT hr = S_OK;
1018
1019 if (fZeroOnRealloc)
1020 {
1021 hr = StrAllocSecure(ppwz, cch);
1022 }
1023 else
1024 {
1025 hr = StrAlloc(ppwz, cch);
1026 }
1027
1028 return hr;
1029}
1030
1031extern "C" HRESULT VariableStrAllocString(
1032 __in BOOL fZeroOnRealloc,
1033 __deref_out_ecount_z(cchSource + 1) LPWSTR* ppwz,
1034 __in_z LPCWSTR wzSource,
1035 __in DWORD_PTR cchSource
1036 )
1037{
1038 HRESULT hr = S_OK;
1039
1040 if (fZeroOnRealloc)
1041 {
1042 hr = StrAllocStringSecure(ppwz, wzSource, cchSource);
1043 }
1044 else
1045 {
1046 hr = StrAllocString(ppwz, wzSource, cchSource);
1047 }
1048
1049 return hr;
1050}
1051
1052extern "C" HRESULT VariableStrAllocConcat(
1053 __in BOOL fZeroOnRealloc,
1054 __deref_out_z LPWSTR* ppwz,
1055 __in_z LPCWSTR wzSource,
1056 __in DWORD_PTR cchSource
1057 )
1058{
1059 HRESULT hr = S_OK;
1060
1061 if (fZeroOnRealloc)
1062 {
1063 hr = StrAllocConcatSecure(ppwz, wzSource, cchSource);
1064 }
1065 else
1066 {
1067 hr = StrAllocConcat(ppwz, wzSource, cchSource);
1068 }
1069
1070 return hr;
1071}
1072
1073extern "C" HRESULT __cdecl VariableStrAllocFormatted(
1074 __in BOOL fZeroOnRealloc,
1075 __deref_out_z LPWSTR* ppwz,
1076 __in __format_string LPCWSTR wzFormat,
1077 ...
1078 )
1079{
1080 HRESULT hr = S_OK;
1081 va_list args;
1082
1083 va_start(args, wzFormat);
1084 if (fZeroOnRealloc)
1085 {
1086 hr = StrAllocFormattedArgsSecure(ppwz, wzFormat, args);
1087 }
1088 else
1089 {
1090 hr = StrAllocFormattedArgs(ppwz, wzFormat, args);
1091 }
1092 va_end(args);
1093
1094 return hr;
1095}
1096
1097extern "C" HRESULT VariableIsHidden(
1098 __in BURN_VARIABLES* pVariables,
1099 __in_z LPCWSTR wzVariable,
1100 __out BOOL* pfHidden
1101 )
1102{
1103 HRESULT hr = S_OK;
1104 BURN_VARIABLE* pVariable = NULL;
1105
1106 ::EnterCriticalSection(&pVariables->csAccess);
1107
1108 hr = GetVariable(pVariables, wzVariable, &pVariable);
1109 if (E_NOTFOUND == hr)
1110 {
1111 // A missing variable does not need its data hidden.
1112 *pfHidden = FALSE;
1113
1114 ExitFunction1(hr = S_OK);
1115 }
1116 ExitOnFailure(hr, "Failed to get visibility of variable: %ls", wzVariable);
1117
1118 *pfHidden = pVariable->fHidden;
1119
1120LExit:
1121 ::LeaveCriticalSection(&pVariables->csAccess);
1122
1123 return hr;
1124}
1125
1126
1127// internal function definitions
1128
1129// The contents of psczOut may be sensitive, should keep encrypted and SecureZeroFree.
1130static HRESULT FormatString(
1131 __in BURN_VARIABLES* pVariables,
1132 __in_z LPCWSTR wzIn,
1133 __out_z_opt LPWSTR* psczOut,
1134 __out_opt DWORD* pcchOut,
1135 __in BOOL fObfuscateHiddenVariables
1136 )
1137{
1138 HRESULT hr = S_OK;
1139 DWORD er = ERROR_SUCCESS;
1140 LPWSTR sczUnformatted = NULL;
1141 LPWSTR sczFormat = NULL;
1142 LPCWSTR wzRead = NULL;
1143 LPCWSTR wzOpen = NULL;
1144 LPCWSTR wzClose = NULL;
1145 LPWSTR scz = NULL;
1146 LPWSTR* rgVariables = NULL;
1147 DWORD cVariables = 0;
1148 DWORD cch = 0;
1149 BOOL fHidden = FALSE;
1150 MSIHANDLE hRecord = NULL;
1151
1152 ::EnterCriticalSection(&pVariables->csAccess);
1153
1154 // allocate buffer for format string
1155 hr = StrAlloc(&sczFormat, lstrlenW(wzIn) + 1);
1156 ExitOnFailure(hr, "Failed to allocate buffer for format string.");
1157
1158 // read out variables from the unformatted string and build a format string
1159 wzRead = wzIn;
1160 for (;;)
1161 {
1162 // scan for opening '['
1163 wzOpen = wcschr(wzRead, L'[');
1164 if (!wzOpen)
1165 {
1166 // end reached, append the remainder of the string and end loop
1167 hr = VariableStrAllocConcat(!fObfuscateHiddenVariables, &sczFormat, wzRead, 0);
1168 ExitOnFailure(hr, "Failed to append string.");
1169 break;
1170 }
1171
1172 // scan for closing ']'
1173 wzClose = wcschr(wzOpen + 1, L']');
1174 if (!wzClose)
1175 {
1176 // end reached, treat unterminated expander as literal
1177 hr = VariableStrAllocConcat(!fObfuscateHiddenVariables, &sczFormat, wzRead, 0);
1178 ExitOnFailure(hr, "Failed to append string.");
1179 break;
1180 }
1181 cch = wzClose - wzOpen - 1;
1182
1183 if (0 == cch)
1184 {
1185 // blank, copy all text including the terminator
1186 hr = VariableStrAllocConcat(!fObfuscateHiddenVariables, &sczFormat, wzRead, (DWORD_PTR)(wzClose - wzRead) + 1);
1187 ExitOnFailure(hr, "Failed to append string.");
1188 }
1189 else
1190 {
1191 // append text preceding expander
1192 if (wzOpen > wzRead)
1193 {
1194 hr = VariableStrAllocConcat(!fObfuscateHiddenVariables, &sczFormat, wzRead, (DWORD_PTR)(wzOpen - wzRead));
1195 ExitOnFailure(hr, "Failed to append string.");
1196 }
1197
1198 // get variable name
1199 hr = VariableStrAllocString(!fObfuscateHiddenVariables, &scz, wzOpen + 1, cch);
1200 ExitOnFailure(hr, "Failed to get variable name.");
1201
1202 // allocate space in variable array
1203 if (rgVariables)
1204 {
1205 LPVOID pv = MemReAlloc(rgVariables, sizeof(LPWSTR) * (cVariables + 1), TRUE);
1206 ExitOnNull(pv, hr, E_OUTOFMEMORY, "Failed to reallocate variable array.");
1207 rgVariables = (LPWSTR*)pv;
1208 }
1209 else
1210 {
1211 rgVariables = (LPWSTR*)MemAlloc(sizeof(LPWSTR) * (cVariables + 1), TRUE);
1212 ExitOnNull(rgVariables, hr, E_OUTOFMEMORY, "Failed to allocate variable array.");
1213 }
1214
1215 // set variable value
1216 if (2 <= cch && L'\\' == wzOpen[1])
1217 {
1218 // escape sequence, copy character
1219 hr = VariableStrAllocString(!fObfuscateHiddenVariables, &rgVariables[cVariables], &wzOpen[2], 1);
1220 }
1221 else
1222 {
1223 if (fObfuscateHiddenVariables)
1224 {
1225 hr = VariableIsHidden(pVariables, scz, &fHidden);
1226 ExitOnFailure(hr, "Failed to determine variable visibility: '%ls'.", scz);
1227 }
1228
1229 if (fHidden)
1230 {
1231 hr = StrAllocString(&rgVariables[cVariables], L"*****", 0);
1232 }
1233 else
1234 {
1235 // get formatted variable value
1236 hr = VariableGetFormatted(pVariables, scz, &rgVariables[cVariables]);
1237 if (E_NOTFOUND == hr) // variable not found
1238 {
1239 hr = StrAllocStringSecure(&rgVariables[cVariables], L"", 0);
1240 }
1241 }
1242 }
1243 ExitOnFailure(hr, "Failed to set variable value.");
1244 ++cVariables;
1245
1246 // append placeholder to format string
1247 hr = VariableStrAllocFormatted(!fObfuscateHiddenVariables, &scz, L"[%d]", cVariables);
1248 ExitOnFailure(hr, "Failed to format placeholder string.");
1249
1250 hr = VariableStrAllocConcat(!fObfuscateHiddenVariables, &sczFormat, scz, 0);
1251 ExitOnFailure(hr, "Failed to append placeholder.");
1252 }
1253
1254 // update read pointer
1255 wzRead = wzClose + 1;
1256 }
1257
1258 // create record
1259 hRecord = ::MsiCreateRecord(cVariables);
1260 ExitOnNull(hRecord, hr, E_OUTOFMEMORY, "Failed to allocate record.");
1261
1262 // set format string
1263 er = ::MsiRecordSetStringW(hRecord, 0, sczFormat);
1264 ExitOnWin32Error(er, hr, "Failed to set record format string.");
1265
1266 // copy record fields
1267 for (DWORD i = 0; i < cVariables; ++i)
1268 {
1269 if (*rgVariables[i]) // not setting if blank
1270 {
1271 er = ::MsiRecordSetStringW(hRecord, i + 1, rgVariables[i]);
1272 ExitOnWin32Error(er, hr, "Failed to set record string.");
1273 }
1274 }
1275
1276 // get formatted character count
1277 cch = 0;
1278#pragma prefast(push)
1279#pragma prefast(disable:6298)
1280 er = ::MsiFormatRecordW(NULL, hRecord, L"", &cch);
1281#pragma prefast(pop)
1282 if (ERROR_MORE_DATA != er)
1283 {
1284 ExitOnWin32Error(er, hr, "Failed to get formatted length.");
1285 }
1286
1287 // return formatted string
1288 if (psczOut)
1289 {
1290 hr = VariableStrAlloc(!fObfuscateHiddenVariables, &scz, ++cch);
1291 ExitOnFailure(hr, "Failed to allocate string.");
1292
1293 er = ::MsiFormatRecordW(NULL, hRecord, scz, &cch);
1294 ExitOnWin32Error(er, hr, "Failed to format record.");
1295
1296 hr = VariableStrAllocString(!fObfuscateHiddenVariables, psczOut, scz, 0);
1297 ExitOnFailure(hr, "Failed to copy string.");
1298 }
1299
1300 // return character count
1301 if (pcchOut)
1302 {
1303 *pcchOut = cch;
1304 }
1305
1306LExit:
1307 ::LeaveCriticalSection(&pVariables->csAccess);
1308
1309 if (rgVariables)
1310 {
1311 for (DWORD i = 0; i < cVariables; ++i)
1312 {
1313 if (fObfuscateHiddenVariables)
1314 {
1315 ReleaseStr(rgVariables[i]);
1316 }
1317 else
1318 {
1319 StrSecureZeroFreeString(rgVariables[i]);
1320 }
1321 }
1322 MemFree(rgVariables);
1323 }
1324
1325 if (hRecord)
1326 {
1327 ::MsiCloseHandle(hRecord);
1328 }
1329
1330 if (fObfuscateHiddenVariables)
1331 {
1332 ReleaseStr(sczUnformatted);
1333 ReleaseStr(sczFormat);
1334 ReleaseStr(scz);
1335 }
1336 else
1337 {
1338 StrSecureZeroFreeString(sczUnformatted);
1339 StrSecureZeroFreeString(sczFormat);
1340 StrSecureZeroFreeString(scz);
1341 }
1342
1343 return hr;
1344}
1345
1346static HRESULT AddBuiltInVariable(
1347 __in BURN_VARIABLES* pVariables,
1348 __in LPCWSTR wzVariable,
1349 __in PFN_INITIALIZEVARIABLE pfnInitialize,
1350 __in DWORD_PTR dwpInitializeData,
1351 __in BOOL fPersist,
1352 __in BOOL fOverridable
1353 )
1354{
1355 HRESULT hr = S_OK;
1356 DWORD iVariable = 0;
1357 BURN_VARIABLE* pVariable = NULL;
1358
1359 hr = FindVariableIndexByName(pVariables, wzVariable, &iVariable);
1360 ExitOnFailure(hr, "Failed to find variable value.");
1361
1362 // insert element if not found
1363 if (S_FALSE == hr)
1364 {
1365 hr = InsertVariable(pVariables, wzVariable, iVariable);
1366 ExitOnFailure(hr, "Failed to insert variable.");
1367 }
1368
1369 // set variable values
1370 pVariable = &pVariables->rgVariables[iVariable];
1371 pVariable->fPersisted = fPersist;
1372 pVariable->internalType = fOverridable ? BURN_VARIABLE_INTERNAL_TYPE_OVERRIDABLE_BUILTIN : BURN_VARIABLE_INTERNAL_TYPE_BUILTIN;
1373 pVariable->pfnInitialize = pfnInitialize;
1374 pVariable->dwpInitializeData = dwpInitializeData;
1375
1376LExit:
1377 return hr;
1378}
1379
1380static HRESULT GetVariable(
1381 __in BURN_VARIABLES* pVariables,
1382 __in_z LPCWSTR wzVariable,
1383 __out BURN_VARIABLE** ppVariable
1384 )
1385{
1386 HRESULT hr = S_OK;
1387 DWORD iVariable = 0;
1388 BURN_VARIABLE* pVariable = NULL;
1389
1390 hr = FindVariableIndexByName(pVariables, wzVariable, &iVariable);
1391 ExitOnFailure(hr, "Failed to find variable value '%ls'.", wzVariable);
1392
1393 if (S_FALSE == hr)
1394 {
1395 ExitFunction1(hr = E_NOTFOUND);
1396 }
1397
1398 pVariable = &pVariables->rgVariables[iVariable];
1399
1400 // initialize built-in variable
1401 if (BURN_VARIANT_TYPE_NONE == pVariable->Value.Type && BURN_VARIABLE_INTERNAL_TYPE_NORMAL < pVariable->internalType)
1402 {
1403 hr = pVariable->pfnInitialize(pVariable->dwpInitializeData, &pVariable->Value);
1404 ExitOnFailure(hr, "Failed to initialize built-in variable value '%ls'.", wzVariable);
1405 }
1406
1407 *ppVariable = pVariable;
1408
1409LExit:
1410 return hr;
1411}
1412
1413static HRESULT FindVariableIndexByName(
1414 __in BURN_VARIABLES* pVariables,
1415 __in_z LPCWSTR wzVariable,
1416 __out DWORD* piVariable
1417 )
1418{
1419 HRESULT hr = S_OK;
1420 DWORD iRangeFirst = 0;
1421 DWORD cRangeLength = pVariables->cVariables;
1422
1423 while (cRangeLength)
1424 {
1425 // get variable in middle of range
1426 DWORD iPosition = cRangeLength / 2;
1427 BURN_VARIABLE* pVariable = &pVariables->rgVariables[iRangeFirst + iPosition];
1428
1429 switch (::CompareStringW(LOCALE_INVARIANT, SORT_STRINGSORT, wzVariable, -1, pVariable->sczName, -1))
1430 {
1431 case CSTR_LESS_THAN:
1432 // restrict range to elements before the current
1433 cRangeLength = iPosition;
1434 break;
1435 case CSTR_EQUAL:
1436 // variable found
1437 *piVariable = iRangeFirst + iPosition;
1438 ExitFunction1(hr = S_OK);
1439 case CSTR_GREATER_THAN:
1440 // restrict range to elements after the current
1441 iRangeFirst += iPosition + 1;
1442 cRangeLength -= iPosition + 1;
1443 break;
1444 default:
1445 ExitWithLastError(hr, "Failed to compare strings.");
1446 }
1447 }
1448
1449 *piVariable = iRangeFirst;
1450 hr = S_FALSE; // variable not found
1451
1452LExit:
1453 return hr;
1454}
1455
1456static HRESULT InsertVariable(
1457 __in BURN_VARIABLES* pVariables,
1458 __in_z LPCWSTR wzVariable,
1459 __in DWORD iPosition
1460 )
1461{
1462 HRESULT hr = S_OK;
1463 size_t cbAllocSize = 0;
1464
1465 // ensure there is room in the variable array
1466 if (pVariables->cVariables == pVariables->dwMaxVariables)
1467 {
1468 hr = ::DWordAdd(pVariables->dwMaxVariables, GROW_VARIABLE_ARRAY, &(pVariables->dwMaxVariables));
1469 ExitOnRootFailure(hr, "Overflow while growing variable array size");
1470
1471 if (pVariables->rgVariables)
1472 {
1473 hr = ::SizeTMult(sizeof(BURN_VARIABLE), pVariables->dwMaxVariables, &cbAllocSize);
1474 ExitOnRootFailure(hr, "Overflow while calculating size of variable array buffer");
1475
1476 LPVOID pv = MemReAlloc(pVariables->rgVariables, cbAllocSize, FALSE);
1477 ExitOnNull(pv, hr, E_OUTOFMEMORY, "Failed to allocate room for more variables.");
1478
1479 // Prefast claims it's possible to hit this. Putting the check in just in case.
1480 if (pVariables->dwMaxVariables < pVariables->cVariables)
1481 {
1482 hr = INTSAFE_E_ARITHMETIC_OVERFLOW;
1483 ExitOnRootFailure(hr, "Overflow while dealing with variable array buffer allocation");
1484 }
1485
1486 pVariables->rgVariables = (BURN_VARIABLE*)pv;
1487 memset(&pVariables->rgVariables[pVariables->cVariables], 0, sizeof(BURN_VARIABLE) * (pVariables->dwMaxVariables - pVariables->cVariables));
1488 }
1489 else
1490 {
1491 pVariables->rgVariables = (BURN_VARIABLE*)MemAlloc(sizeof(BURN_VARIABLE) * pVariables->dwMaxVariables, TRUE);
1492 ExitOnNull(pVariables->rgVariables, hr, E_OUTOFMEMORY, "Failed to allocate room for variables.");
1493 }
1494 }
1495
1496 // move variables
1497 if (0 < pVariables->cVariables - iPosition)
1498 {
1499 memmove(&pVariables->rgVariables[iPosition + 1], &pVariables->rgVariables[iPosition], sizeof(BURN_VARIABLE) * (pVariables->cVariables - iPosition));
1500 memset(&pVariables->rgVariables[iPosition], 0, sizeof(BURN_VARIABLE));
1501 }
1502
1503 ++pVariables->cVariables;
1504
1505 // allocate name
1506 hr = StrAllocString(&pVariables->rgVariables[iPosition].sczName, wzVariable, 0);
1507 ExitOnFailure(hr, "Failed to copy variable name.");
1508
1509LExit:
1510 return hr;
1511}
1512
1513static HRESULT SetVariableValue(
1514 __in BURN_VARIABLES* pVariables,
1515 __in_z LPCWSTR wzVariable,
1516 __in BURN_VARIANT* pVariant,
1517 __in BOOL fLiteral,
1518 __in SET_VARIABLE setBuiltin,
1519 __in BOOL fLog
1520 )
1521{
1522 HRESULT hr = S_OK;
1523 DWORD iVariable = 0;
1524
1525 ::EnterCriticalSection(&pVariables->csAccess);
1526
1527 hr = FindVariableIndexByName(pVariables, wzVariable, &iVariable);
1528 ExitOnFailure(hr, "Failed to find variable value '%ls'.", wzVariable);
1529
1530 // Insert element if not found.
1531 if (S_FALSE == hr)
1532 {
1533 hr = InsertVariable(pVariables, wzVariable, iVariable);
1534 ExitOnFailure(hr, "Failed to insert variable '%ls'.", wzVariable);
1535 }
1536 else if (BURN_VARIABLE_INTERNAL_TYPE_NORMAL < pVariables->rgVariables[iVariable].internalType) // built-in variables must be overridden.
1537 {
1538 if (SET_VARIABLE_OVERRIDE_BUILTIN == setBuiltin ||
1539 (SET_VARIABLE_OVERRIDE_PERSISTED_BUILTINS == setBuiltin && pVariables->rgVariables[iVariable].fPersisted) ||
1540 SET_VARIABLE_ANY == setBuiltin && BURN_VARIABLE_INTERNAL_TYPE_BUILTIN != pVariables->rgVariables[iVariable].internalType)
1541 {
1542 hr = S_OK;
1543 }
1544 else
1545 {
1546 hr = E_INVALIDARG;
1547 ExitOnRootFailure(hr, "Attempt to set built-in variable value: %ls", wzVariable);
1548 }
1549 }
1550 else // must *not* be a built-in variable so caller should not have tried to override it as a built-in.
1551 {
1552 // Not possible from external callers so just assert.
1553 AssertSz(SET_VARIABLE_OVERRIDE_BUILTIN != setBuiltin, "Intent to overwrite non-built-in variable.");
1554 }
1555
1556 // Log value when not overwriting a built-in variable.
1557 if (fLog && BURN_VARIABLE_INTERNAL_TYPE_NORMAL == pVariables->rgVariables[iVariable].internalType)
1558 {
1559 if (pVariables->rgVariables[iVariable].fHidden)
1560 {
1561 LogStringLine(REPORT_STANDARD, "Setting hidden variable '%ls'", wzVariable);
1562 }
1563 else
1564 {
1565 // Assume value isn't encrypted since it's not hidden.
1566 switch (pVariant->Type)
1567 {
1568 case BURN_VARIANT_TYPE_NONE:
1569 if (BURN_VARIANT_TYPE_NONE != pVariables->rgVariables[iVariable].Value.Type)
1570 {
1571 LogStringLine(REPORT_STANDARD, "Unsetting variable '%ls'", wzVariable, pVariant->sczValue);
1572 }
1573 break;
1574
1575 case BURN_VARIANT_TYPE_NUMERIC:
1576 LogStringLine(REPORT_STANDARD, "Setting numeric variable '%ls' to value %lld", wzVariable, pVariant->llValue);
1577 break;
1578
1579 case BURN_VARIANT_TYPE_STRING:
1580 if (!pVariant->sczValue)
1581 {
1582 LogStringLine(REPORT_STANDARD, "Unsetting variable '%ls'", wzVariable, pVariant->sczValue);
1583 }
1584 else
1585 {
1586 LogStringLine(REPORT_STANDARD, "Setting string variable '%ls' to value '%ls'", wzVariable, pVariant->sczValue);
1587 }
1588 break;
1589
1590 case BURN_VARIANT_TYPE_VERSION:
1591 LogStringLine(REPORT_STANDARD, "Setting version variable '%ls' to value '%hu.%hu.%hu.%hu'", wzVariable, (WORD)(pVariant->qwValue >> 48), (WORD)(pVariant->qwValue >> 32), (WORD)(pVariant->qwValue >> 16), (WORD)(pVariant->qwValue));
1592 break;
1593
1594 default:
1595 AssertSz(FALSE, "Unknown variant type.");
1596 break;
1597 }
1598 }
1599 }
1600
1601 // Update variable value.
1602 hr = BVariantSetValue(&pVariables->rgVariables[iVariable].Value, pVariant);
1603 ExitOnFailure(hr, "Failed to set value of variable: %ls", wzVariable);
1604
1605 // Update variable literal flag.
1606 pVariables->rgVariables[iVariable].fLiteral = fLiteral;
1607
1608LExit:
1609 ::LeaveCriticalSection(&pVariables->csAccess);
1610
1611 if (FAILED(hr) && fLog)
1612 {
1613 LogStringLine(REPORT_STANDARD, "Setting variable failed: ID '%ls', HRESULT 0x%x", wzVariable, hr);
1614 }
1615
1616 return hr;
1617}
1618
1619extern "C" typedef NTSTATUS (NTAPI *RTL_GET_VERSION)(_Out_ PRTL_OSVERSIONINFOEXW lpVersionInformation);
1620
1621static HRESULT InitializeVariableVersionNT(
1622 __in DWORD_PTR dwpData,
1623 __inout BURN_VARIANT* pValue
1624 )
1625{
1626 HRESULT hr = S_OK;
1627 HMODULE ntdll = NULL;
1628 RTL_GET_VERSION rtlGetVersion = NULL;
1629 RTL_OSVERSIONINFOEXW ovix = { };
1630 BURN_VARIANT value = { };
1631
1632 if (!::GetModuleHandleExW(0, L"ntdll", &ntdll))
1633 {
1634 ExitWithLastError(hr, "Failed to locate NTDLL.");
1635 }
1636
1637 rtlGetVersion = reinterpret_cast<RTL_GET_VERSION>(::GetProcAddress(ntdll, "RtlGetVersion"));
1638 if (NULL == rtlGetVersion)
1639 {
1640 ExitWithLastError(hr, "Failed to locate RtlGetVersion.");
1641 }
1642
1643 ovix.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
1644 hr = static_cast<HRESULT>(rtlGetVersion(&ovix));
1645 ExitOnFailure(hr, "Failed to get OS info.");
1646
1647 switch ((OS_INFO_VARIABLE)dwpData)
1648 {
1649 case OS_INFO_VARIABLE_ServicePackLevel:
1650 if (0 != ovix.wServicePackMajor)
1651 {
1652 value.qwValue = static_cast<DWORD64>(ovix.wServicePackMajor);
1653 value.Type = BURN_VARIANT_TYPE_NUMERIC;
1654 }
1655 break;
1656 case OS_INFO_VARIABLE_VersionNT:
1657 value.qwValue = MAKEQWORDVERSION(ovix.dwMajorVersion, ovix.dwMinorVersion, 0, 0);
1658 value.Type = BURN_VARIANT_TYPE_VERSION;
1659 break;
1660 case OS_INFO_VARIABLE_VersionNT64:
1661 {
1662#if !defined(_WIN64)
1663 BOOL fIsWow64 = FALSE;
1664
1665 ProcWow64(::GetCurrentProcess(), &fIsWow64);
1666 if (fIsWow64)
1667#endif
1668 {
1669 value.qwValue = MAKEQWORDVERSION(ovix.dwMajorVersion, ovix.dwMinorVersion, 0, 0);
1670 value.Type = BURN_VARIANT_TYPE_VERSION;
1671 }
1672 }
1673 break;
1674 default:
1675 AssertSz(FALSE, "Unknown OS info type.");
1676 break;
1677 }
1678
1679 hr = BVariantCopy(&value, pValue);
1680 ExitOnFailure(hr, "Failed to set variant value.");
1681
1682LExit:
1683 if (NULL != ntdll)
1684 {
1685 FreeLibrary(ntdll);
1686 }
1687
1688 return hr;
1689}
1690
1691static HRESULT InitializeVariableOsInfo(
1692 __in DWORD_PTR dwpData,
1693 __inout BURN_VARIANT* pValue
1694 )
1695{
1696 HRESULT hr = S_OK;
1697 OSVERSIONINFOEXW ovix = { };
1698 BURN_VARIANT value = { };
1699
1700 ovix.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
1701 if (!::GetVersionExW((LPOSVERSIONINFOW)&ovix))
1702 {
1703 ExitWithLastError(hr, "Failed to get OS info.");
1704 }
1705
1706 switch ((OS_INFO_VARIABLE)dwpData)
1707 {
1708 case OS_INFO_VARIABLE_NTProductType:
1709 value.llValue = ovix.wProductType;
1710 value.Type = BURN_VARIANT_TYPE_NUMERIC;
1711 break;
1712 case OS_INFO_VARIABLE_NTSuiteBackOffice:
1713 value.llValue = VER_SUITE_BACKOFFICE & ovix.wSuiteMask ? 1 : 0;
1714 value.Type = BURN_VARIANT_TYPE_NUMERIC;
1715 break;
1716 case OS_INFO_VARIABLE_NTSuiteDataCenter:
1717 value.llValue = VER_SUITE_DATACENTER & ovix.wSuiteMask ? 1 : 0;
1718 value.Type = BURN_VARIANT_TYPE_NUMERIC;
1719 break;
1720 case OS_INFO_VARIABLE_NTSuiteEnterprise:
1721 value.llValue = VER_SUITE_ENTERPRISE & ovix.wSuiteMask ? 1 : 0;
1722 value.Type = BURN_VARIANT_TYPE_NUMERIC;
1723 break;
1724 case OS_INFO_VARIABLE_NTSuitePersonal:
1725 value.llValue = VER_SUITE_PERSONAL & ovix.wSuiteMask ? 1 : 0;
1726 value.Type = BURN_VARIANT_TYPE_NUMERIC;
1727 break;
1728 case OS_INFO_VARIABLE_NTSuiteSmallBusiness:
1729 value.llValue = VER_SUITE_SMALLBUSINESS & ovix.wSuiteMask ? 1 : 0;
1730 value.Type = BURN_VARIANT_TYPE_NUMERIC;
1731 break;
1732 case OS_INFO_VARIABLE_NTSuiteSmallBusinessRestricted:
1733 value.llValue = VER_SUITE_SMALLBUSINESS_RESTRICTED & ovix.wSuiteMask ? 1 : 0;
1734 value.Type = BURN_VARIANT_TYPE_NUMERIC;
1735 break;
1736 case OS_INFO_VARIABLE_NTSuiteWebServer:
1737 value.llValue = VER_SUITE_BLADE & ovix.wSuiteMask ? 1 : 0;
1738 value.Type = BURN_VARIANT_TYPE_NUMERIC;
1739 break;
1740 case OS_INFO_VARIABLE_CompatibilityMode:
1741 {
1742 DWORDLONG dwlConditionMask = 0;
1743 VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_EQUAL);
1744 VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, VER_EQUAL);
1745 VER_SET_CONDITION(dwlConditionMask, VER_SERVICEPACKMAJOR, VER_EQUAL);
1746 VER_SET_CONDITION(dwlConditionMask, VER_SERVICEPACKMINOR, VER_EQUAL);
1747
1748 value.llValue = ::VerifyVersionInfoW(&ovix, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, dwlConditionMask);
1749 value.Type = BURN_VARIANT_TYPE_NUMERIC;
1750 }
1751 break;
1752 case OS_INFO_VARIABLE_TerminalServer:
1753 value.llValue = (VER_SUITE_TERMINAL == (ovix.wSuiteMask & VER_SUITE_TERMINAL)) && (VER_SUITE_SINGLEUSERTS != (ovix.wSuiteMask & VER_SUITE_SINGLEUSERTS)) ? 1 : 0;
1754 value.Type = BURN_VARIANT_TYPE_NUMERIC;
1755 break;
1756 default:
1757 AssertSz(FALSE, "Unknown OS info type.");
1758 break;
1759 }
1760
1761 hr = BVariantCopy(&value, pValue);
1762 ExitOnFailure(hr, "Failed to set variant value.");
1763
1764LExit:
1765 return hr;
1766}
1767
1768static HRESULT InitializeVariableSystemInfo(
1769 __in DWORD_PTR dwpData,
1770 __inout BURN_VARIANT* pValue
1771 )
1772{
1773 HRESULT hr = S_OK;
1774 SYSTEM_INFO si = { };
1775 BURN_VARIANT value = { };
1776
1777 ::GetNativeSystemInfo(&si);
1778
1779 switch ((OS_INFO_VARIABLE)dwpData)
1780 {
1781 case OS_INFO_VARIABLE_ProcessorArchitecture:
1782 value.llValue = si.wProcessorArchitecture;
1783 value.Type = BURN_VARIANT_TYPE_NUMERIC;
1784 break;
1785 default:
1786 AssertSz(FALSE, "Unknown OS info type.");
1787 break;
1788 }
1789
1790 hr = BVariantCopy(&value, pValue);
1791 ExitOnFailure(hr, "Failed to set variant value.");
1792
1793LExit:
1794 return hr;
1795}
1796
1797static HRESULT InitializeVariableComputerName(
1798 __in DWORD_PTR dwpData,
1799 __inout BURN_VARIANT* pValue
1800 )
1801{
1802 UNREFERENCED_PARAMETER(dwpData);
1803
1804 HRESULT hr = S_OK;
1805 WCHAR wzComputerName[MAX_COMPUTERNAME_LENGTH + 1] = { };
1806 DWORD cchComputerName = countof(wzComputerName);
1807
1808 // get computer name
1809 if (!::GetComputerNameW(wzComputerName, &cchComputerName))
1810 {
1811 ExitWithLastError(hr, "Failed to get computer name.");
1812 }
1813
1814 // set value
1815 hr = BVariantSetString(pValue, wzComputerName, 0);
1816 ExitOnFailure(hr, "Failed to set variant value.");
1817
1818LExit:
1819 return hr;
1820}
1821
1822static HRESULT InitializeVariableVersionMsi(
1823 __in DWORD_PTR dwpData,
1824 __inout BURN_VARIANT* pValue
1825 )
1826{
1827 UNREFERENCED_PARAMETER(dwpData);
1828
1829 HRESULT hr = S_OK;
1830 DLLGETVERSIONPROC pfnMsiDllGetVersion = NULL;
1831 DLLVERSIONINFO msiVersionInfo = { };
1832
1833 // get DllGetVersion proc address
1834 pfnMsiDllGetVersion = (DLLGETVERSIONPROC)::GetProcAddress(::GetModuleHandleW(L"msi"), "DllGetVersion");
1835 ExitOnNullWithLastError(pfnMsiDllGetVersion, hr, "Failed to find DllGetVersion entry point in msi.dll.");
1836
1837 // get msi.dll version info
1838 msiVersionInfo.cbSize = sizeof(DLLVERSIONINFO);
1839 hr = pfnMsiDllGetVersion(&msiVersionInfo);
1840 ExitOnFailure(hr, "Failed to get msi.dll version info.");
1841
1842 hr = BVariantSetVersion(pValue, MAKEQWORDVERSION(msiVersionInfo.dwMajorVersion, msiVersionInfo.dwMinorVersion, 0, 0));
1843 ExitOnFailure(hr, "Failed to set variant value.");
1844
1845LExit:
1846 return hr;
1847}
1848
1849static HRESULT InitializeVariableCsidlFolder(
1850 __in DWORD_PTR dwpData,
1851 __inout BURN_VARIANT* pValue
1852 )
1853{
1854 HRESULT hr = S_OK;
1855 LPWSTR sczPath = NULL;
1856 int nFolder = (int)dwpData;
1857
1858 // get folder path
1859 hr = ShelGetFolder(&sczPath, nFolder);
1860 ExitOnRootFailure(hr, "Failed to get shell folder.");
1861
1862 // set value
1863 hr = BVariantSetString(pValue, sczPath, 0);
1864 ExitOnFailure(hr, "Failed to set variant value.");
1865
1866LExit:
1867 ReleaseStr(sczPath);
1868
1869 return hr;
1870}
1871
1872static HRESULT InitializeVariableTempFolder(
1873 __in DWORD_PTR dwpData,
1874 __inout BURN_VARIANT* pValue
1875 )
1876{
1877 UNREFERENCED_PARAMETER(dwpData);
1878
1879 HRESULT hr = S_OK;
1880 WCHAR wzPath[MAX_PATH] = { };
1881
1882 // get volume path name
1883 if (!::GetTempPathW(MAX_PATH, wzPath))
1884 {
1885 ExitWithLastError(hr, "Failed to get temp path.");
1886 }
1887
1888 // set value
1889 hr = BVariantSetString(pValue, wzPath, 0);
1890 ExitOnFailure(hr, "Failed to set variant value.");
1891
1892LExit:
1893 return hr;
1894}
1895
1896static HRESULT InitializeVariableSystemFolder(
1897 __in DWORD_PTR dwpData,
1898 __inout BURN_VARIANT* pValue
1899 )
1900{
1901 HRESULT hr = S_OK;
1902 BOOL f64 = (BOOL)dwpData;
1903 WCHAR wzSystemFolder[MAX_PATH] = { };
1904
1905#if !defined(_WIN64)
1906 BOOL fIsWow64 = FALSE;
1907 ProcWow64(::GetCurrentProcess(), &fIsWow64);
1908
1909 if (fIsWow64)
1910 {
1911 if (f64)
1912 {
1913 if (!::GetSystemDirectoryW(wzSystemFolder, countof(wzSystemFolder)))
1914 {
1915 ExitWithLastError(hr, "Failed to get 64-bit system folder.");
1916 }
1917 }
1918 else
1919 {
1920 if (!::GetSystemWow64DirectoryW(wzSystemFolder, countof(wzSystemFolder)))
1921 {
1922 ExitWithLastError(hr, "Failed to get 32-bit system folder.");
1923 }
1924 }
1925 }
1926 else
1927 {
1928 if (!f64)
1929 {
1930 if (!::GetSystemDirectoryW(wzSystemFolder, countof(wzSystemFolder)))
1931 {
1932 ExitWithLastError(hr, "Failed to get 32-bit system folder.");
1933 }
1934 }
1935 }
1936#else
1937 if (f64)
1938 {
1939 if (!::GetSystemDirectoryW(wzSystemFolder, countof(wzSystemFolder)))
1940 {
1941 ExitWithLastError(hr, "Failed to get 64-bit system folder.");
1942 }
1943 }
1944 else
1945 {
1946 if (!::GetSystemWow64DirectoryW(wzSystemFolder, countof(wzSystemFolder)))
1947 {
1948 ExitWithLastError(hr, "Failed to get 32-bit system folder.");
1949 }
1950 }
1951#endif
1952
1953 if (*wzSystemFolder)
1954 {
1955 hr = PathFixedBackslashTerminate(wzSystemFolder, countof(wzSystemFolder));
1956 ExitOnFailure(hr, "Failed to backslash terminate system folder.");
1957 }
1958
1959 // set value
1960 hr = BVariantSetString(pValue, wzSystemFolder, 0);
1961 ExitOnFailure(hr, "Failed to set system folder variant value.");
1962
1963LExit:
1964 return hr;
1965}
1966
1967static HRESULT InitializeVariableWindowsVolumeFolder(
1968 __in DWORD_PTR dwpData,
1969 __inout BURN_VARIANT* pValue
1970 )
1971{
1972 UNREFERENCED_PARAMETER(dwpData);
1973
1974 HRESULT hr = S_OK;
1975 WCHAR wzWindowsPath[MAX_PATH] = { };
1976 WCHAR wzVolumePath[MAX_PATH] = { };
1977
1978 // get windows directory
1979 if (!::GetWindowsDirectoryW(wzWindowsPath, countof(wzWindowsPath)))
1980 {
1981 ExitWithLastError(hr, "Failed to get windows directory.");
1982 }
1983
1984 // get volume path name
1985 if (!::GetVolumePathNameW(wzWindowsPath, wzVolumePath, MAX_PATH))
1986 {
1987 ExitWithLastError(hr, "Failed to get volume path name.");
1988 }
1989
1990 // set value
1991 hr = BVariantSetString(pValue, wzVolumePath, 0);
1992 ExitOnFailure(hr, "Failed to set variant value.");
1993
1994LExit:
1995 return hr;
1996}
1997
1998static HRESULT InitializeVariablePrivileged(
1999 __in DWORD_PTR dwpData,
2000 __inout BURN_VARIANT* pValue
2001 )
2002{
2003 UNREFERENCED_PARAMETER(dwpData);
2004
2005 HRESULT hr = S_OK;
2006 BOOL fPrivileged = FALSE;
2007
2008 // check if process could run privileged.
2009 hr = OsCouldRunPrivileged(&fPrivileged);
2010 ExitOnFailure(hr, "Failed to check if process could run privileged.");
2011
2012 // set value
2013 hr = BVariantSetNumeric(pValue, fPrivileged);
2014 ExitOnFailure(hr, "Failed to set variant value.");
2015
2016LExit:
2017 return hr;
2018}
2019
2020static HRESULT InitializeVariableRebootPending(
2021 __in DWORD_PTR dwpData,
2022 __inout BURN_VARIANT* pValue
2023 )
2024{
2025 UNREFERENCED_PARAMETER(dwpData);
2026
2027 HRESULT hr = S_OK;
2028 BOOL fRebootPending = FALSE;
2029 BOOL fComInitialized = FALSE;
2030
2031 // Do a best effort to ask WU if a reboot is required. If anything goes
2032 // wrong then let's pretend a reboot is not required.
2033 hr = ::CoInitialize(NULL);
2034 if (SUCCEEDED(hr) || RPC_E_CHANGED_MODE == hr)
2035 {
2036 fComInitialized = TRUE;
2037
2038 hr = WuaRestartRequired(&fRebootPending);
2039 if (FAILED(hr))
2040 {
2041 fRebootPending = FALSE;
2042 hr = S_OK;
2043 }
2044 }
2045
2046 hr = BVariantSetNumeric(pValue, fRebootPending);
2047 ExitOnFailure(hr, "Failed to set reboot pending variant value.");
2048
2049LExit:
2050 if (fComInitialized)
2051 {
2052 ::CoUninitialize();
2053 }
2054
2055 return hr;
2056}
2057
2058static HRESULT InitializeSystemLanguageID(
2059 __in DWORD_PTR dwpData,
2060 __inout BURN_VARIANT* pValue
2061 )
2062{
2063 UNREFERENCED_PARAMETER(dwpData);
2064
2065 HRESULT hr = S_OK;
2066 LANGID langid = ::GetSystemDefaultLangID();
2067
2068 hr = BVariantSetNumeric(pValue, langid);
2069 ExitOnFailure(hr, "Failed to set variant value.");
2070
2071LExit:
2072 return hr;
2073}
2074
2075static HRESULT InitializeUserUILanguageID(
2076 __in DWORD_PTR dwpData,
2077 __inout BURN_VARIANT* pValue
2078 )
2079{
2080 UNREFERENCED_PARAMETER(dwpData);
2081
2082 HRESULT hr = S_OK;
2083 LANGID langid = ::GetUserDefaultUILanguage();
2084
2085 hr = BVariantSetNumeric(pValue, langid);
2086 ExitOnFailure(hr, "Failed to set variant value.");
2087
2088LExit:
2089 return hr;
2090}
2091
2092static HRESULT InitializeUserLanguageID(
2093 __in DWORD_PTR dwpData,
2094 __inout BURN_VARIANT* pValue
2095 )
2096{
2097 UNREFERENCED_PARAMETER(dwpData);
2098
2099 HRESULT hr = S_OK;
2100 LANGID langid = ::GetUserDefaultLangID();
2101
2102 hr = BVariantSetNumeric(pValue, langid);
2103 ExitOnFailure(hr, "Failed to set variant value.");
2104
2105LExit:
2106 return hr;
2107}
2108
2109static HRESULT InitializeVariableString(
2110 __in DWORD_PTR dwpData,
2111 __inout BURN_VARIANT* pValue
2112 )
2113{
2114 HRESULT hr = S_OK;
2115 LPCWSTR wzValue = (LPCWSTR)dwpData;
2116
2117 // set value
2118 hr = BVariantSetString(pValue, wzValue, 0);
2119 ExitOnFailure(hr, "Failed to set variant value.");
2120
2121LExit:
2122 return hr;
2123}
2124
2125static HRESULT InitializeVariableNumeric(
2126 __in DWORD_PTR dwpData,
2127 __inout BURN_VARIANT* pValue
2128 )
2129{
2130 HRESULT hr = S_OK;
2131 LONGLONG llValue = (LONGLONG)dwpData;
2132
2133 // set value
2134 hr = BVariantSetNumeric(pValue, llValue);
2135 ExitOnFailure(hr, "Failed to set variant value.");
2136
2137LExit:
2138 return hr;
2139}
2140
2141static HRESULT InitializeVariableRegistryFolder(
2142 __in DWORD_PTR dwpData,
2143 __inout BURN_VARIANT* pValue
2144 )
2145{
2146 HRESULT hr = S_OK;
2147 int nFolder = (int)dwpData;
2148 LPWSTR sczPath = NULL;
2149
2150#if !defined(_WIN64)
2151 BOOL fIsWow64 = FALSE;
2152
2153 ProcWow64(::GetCurrentProcess(), &fIsWow64);
2154 if (!fIsWow64) // on 32-bit machines, variables aren't set
2155 {
2156 ExitFunction();
2157 }
2158#endif
2159
2160 hr = Get64bitFolderFromRegistry(nFolder, &sczPath);
2161 ExitOnFailure(hr, "Failed to get 64-bit folder.");
2162
2163 // set value
2164 hr = BVariantSetString(pValue, sczPath, 0);
2165 ExitOnFailure(hr, "Failed to set variant value.");
2166
2167LExit:
2168 ReleaseStr(sczPath);
2169
2170 return hr;
2171}
2172
2173static HRESULT InitializeVariable6432Folder(
2174 __in DWORD_PTR dwpData,
2175 __inout BURN_VARIANT* pValue
2176 )
2177{
2178 HRESULT hr = S_OK;
2179 int nFolder = (int)dwpData;
2180 LPWSTR sczPath = NULL;
2181
2182#if !defined(_WIN64)
2183 BOOL fIsWow64 = FALSE;
2184
2185 // If 32-bit use shell-folder.
2186 ProcWow64(::GetCurrentProcess(), &fIsWow64);
2187 if (!fIsWow64)
2188 {
2189 hr = ShelGetFolder(&sczPath, nFolder);
2190 ExitOnRootFailure(hr, "Failed to get shell folder.");
2191 }
2192 else
2193#endif
2194 {
2195 hr = Get64bitFolderFromRegistry(nFolder, &sczPath);
2196 ExitOnFailure(hr, "Failed to get 64-bit folder.");
2197 }
2198
2199 // set value
2200 hr = BVariantSetString(pValue, sczPath, 0);
2201 ExitOnFailure(hr, "Failed to set variant value.");
2202
2203LExit:
2204 ReleaseStr(sczPath);
2205
2206 return hr;
2207}
2208
2209// Get the date in the same format as Windows Installer.
2210static HRESULT InitializeVariableDate(
2211 __in DWORD_PTR /*dwpData*/,
2212 __inout BURN_VARIANT* pValue
2213 )
2214{
2215 HRESULT hr = S_OK;
2216 SYSTEMTIME systime = { };
2217 LPWSTR sczDate = NULL;
2218 int cchDate = 0;
2219
2220 ::GetSystemTime(&systime);
2221
2222 cchDate = ::GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &systime, NULL, NULL, cchDate);
2223 if (!cchDate)
2224 {
2225 ExitOnLastError(hr, "Failed to get the required buffer length for the Date.");
2226 }
2227
2228 hr = StrAlloc(&sczDate, cchDate);
2229 ExitOnFailure(hr, "Failed to allocate the buffer for the Date.");
2230
2231 if (!::GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &systime, NULL, sczDate, cchDate))
2232 {
2233 ExitOnLastError(hr, "Failed to get the Date.");
2234 }
2235
2236 // set value
2237 hr = BVariantSetString(pValue, sczDate, cchDate);
2238 ExitOnFailure(hr, "Failed to set variant value.");
2239
2240LExit:
2241 ReleaseStr(sczDate);
2242
2243 return hr;
2244}
2245
2246static HRESULT InitializeVariableInstallerName(
2247 __in DWORD_PTR /*dwpData*/,
2248 __inout BURN_VARIANT* pValue
2249 )
2250{
2251 HRESULT hr = S_OK;
2252
2253 // set value
2254 hr = BVariantSetString(pValue, L"WiX Burn", 0);
2255 ExitOnFailure(hr, "Failed to set variant value.");
2256
2257LExit:
2258 return hr;
2259}
2260
2261static HRESULT InitializeVariableInstallerVersion(
2262 __in DWORD_PTR /*dwpData*/,
2263 __inout BURN_VARIANT* pValue
2264 )
2265{
2266 HRESULT hr = S_OK;
2267 LPWSTR sczVersion = NULL;
2268
2269 hr = StrAllocStringAnsi(&sczVersion, szVerMajorMinorBuild, 0, CP_ACP);
2270 ExitOnFailure(hr, "Failed to copy the engine version.");
2271
2272 // set value
2273 hr = BVariantSetString(pValue, sczVersion, 0);
2274 ExitOnFailure(hr, "Failed to set variant value.");
2275
2276LExit:
2277 ReleaseStr(sczVersion);
2278
2279 return hr;
2280}
2281
2282static HRESULT InitializeVariableVersion(
2283 __in DWORD_PTR dwpData,
2284 __inout BURN_VARIANT* pValue
2285 )
2286{
2287 HRESULT hr = S_OK;
2288
2289 // set value
2290 hr = BVariantSetVersion(pValue, static_cast<DWORD64>(dwpData));
2291 ExitOnFailure(hr, "Failed to set variant value.");
2292
2293LExit:
2294 return hr;
2295}
2296
2297// Get the current user the same as Windows Installer.
2298static HRESULT InitializeVariableLogonUser(
2299 __in DWORD_PTR /*dwpData*/,
2300 __inout BURN_VARIANT* pValue
2301 )
2302{
2303 HRESULT hr = S_OK;
2304 WCHAR wzUserName[UNLEN + 1];
2305 DWORD cchUserName = countof(wzUserName);
2306
2307 if (!::GetUserNameW(wzUserName, &cchUserName))
2308 {
2309 ExitOnLastError(hr, "Failed to get the user name.");
2310 }
2311
2312 // set value
2313 hr = BVariantSetString(pValue, wzUserName, 0);
2314 ExitOnFailure(hr, "Failed to set variant value.");
2315
2316LExit:
2317 return hr;
2318}
2319
2320static HRESULT Get64bitFolderFromRegistry(
2321 __in int nFolder,
2322 __deref_out_z LPWSTR* psczPath
2323 )
2324{
2325 HRESULT hr = S_OK;
2326 HKEY hkFolders = NULL;
2327
2328 AssertSz(CSIDL_PROGRAM_FILES == nFolder || CSIDL_PROGRAM_FILES_COMMON == nFolder, "Unknown folder CSIDL.");
2329 LPCWSTR wzFolderValue = CSIDL_PROGRAM_FILES_COMMON == nFolder ? L"CommonFilesDir" : L"ProgramFilesDir";
2330
2331 hr = RegOpen(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion", KEY_READ | KEY_WOW64_64KEY, &hkFolders);
2332 ExitOnFailure(hr, "Failed to open Windows folder key.");
2333
2334 hr = RegReadString(hkFolders, wzFolderValue, psczPath);
2335 ExitOnFailure(hr, "Failed to read folder path for '%ls'.", wzFolderValue);
2336
2337 hr = PathBackslashTerminate(psczPath);
2338 ExitOnFailure(hr, "Failed to ensure path was backslash terminated.");
2339
2340LExit:
2341 ReleaseRegKey(hkFolders);
2342
2343 return hr;
2344}
2345