diff options
author | Sean Hall <r.sean.hall@gmail.com> | 2018-12-29 22:12:08 -0600 |
---|---|---|
committer | Sean Hall <r.sean.hall@gmail.com> | 2018-12-29 22:12:08 -0600 |
commit | 61847dddd4fd497057c780658e383c4627de19ec (patch) | |
tree | f85a845182922538ab9aa6ee85b0db3ab40c1f6e /src/engine/variable.cpp | |
parent | 8295f5f8fd28042e1a0a172d5afbba79178064c2 (diff) | |
download | wix-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.cpp | 2345 |
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 | |||
8 | typedef 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 | |||
20 | const DWORD GROW_VARIABLE_ARRAY = 3; | ||
21 | |||
22 | enum 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 | |||
41 | enum 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 | |||
51 | static 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 | ); | ||
58 | static 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 | ); | ||
66 | static HRESULT GetVariable( | ||
67 | __in BURN_VARIABLES* pVariables, | ||
68 | __in_z LPCWSTR wzVariable, | ||
69 | __out BURN_VARIABLE** ppVariable | ||
70 | ); | ||
71 | static HRESULT FindVariableIndexByName( | ||
72 | __in BURN_VARIABLES* pVariables, | ||
73 | __in_z LPCWSTR wzVariable, | ||
74 | __out DWORD* piVariable | ||
75 | ); | ||
76 | static HRESULT InsertVariable( | ||
77 | __in BURN_VARIABLES* pVariables, | ||
78 | __in_z LPCWSTR wzVariable, | ||
79 | __in DWORD iPosition | ||
80 | ); | ||
81 | static 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 | ); | ||
89 | static HRESULT InitializeVariableVersionNT( | ||
90 | __in DWORD_PTR dwpData, | ||
91 | __inout BURN_VARIANT* pValue | ||
92 | ); | ||
93 | static HRESULT InitializeVariableOsInfo( | ||
94 | __in DWORD_PTR dwpData, | ||
95 | __inout BURN_VARIANT* pValue | ||
96 | ); | ||
97 | static HRESULT InitializeVariableSystemInfo( | ||
98 | __in DWORD_PTR dwpData, | ||
99 | __inout BURN_VARIANT* pValue | ||
100 | ); | ||
101 | static HRESULT InitializeVariableComputerName( | ||
102 | __in DWORD_PTR dwpData, | ||
103 | __inout BURN_VARIANT* pValue | ||
104 | ); | ||
105 | static HRESULT InitializeVariableVersionMsi( | ||
106 | __in DWORD_PTR dwpData, | ||
107 | __inout BURN_VARIANT* pValue | ||
108 | ); | ||
109 | static HRESULT InitializeVariableCsidlFolder( | ||
110 | __in DWORD_PTR dwpData, | ||
111 | __inout BURN_VARIANT* pValue | ||
112 | ); | ||
113 | static HRESULT InitializeVariableWindowsVolumeFolder( | ||
114 | __in DWORD_PTR dwpData, | ||
115 | __inout BURN_VARIANT* pValue | ||
116 | ); | ||
117 | static HRESULT InitializeVariableTempFolder( | ||
118 | __in DWORD_PTR dwpData, | ||
119 | __inout BURN_VARIANT* pValue | ||
120 | ); | ||
121 | static HRESULT InitializeVariableSystemFolder( | ||
122 | __in DWORD_PTR dwpData, | ||
123 | __inout BURN_VARIANT* pValue | ||
124 | ); | ||
125 | static HRESULT InitializeVariablePrivileged( | ||
126 | __in DWORD_PTR dwpData, | ||
127 | __inout BURN_VARIANT* pValue | ||
128 | ); | ||
129 | static HRESULT InitializeVariableRebootPending( | ||
130 | __in DWORD_PTR dwpData, | ||
131 | __inout BURN_VARIANT* pValue | ||
132 | ); | ||
133 | static HRESULT InitializeSystemLanguageID( | ||
134 | __in DWORD_PTR dwpData, | ||
135 | __inout BURN_VARIANT* pValue | ||
136 | ); | ||
137 | static HRESULT InitializeUserUILanguageID( | ||
138 | __in DWORD_PTR dwpData, | ||
139 | __inout BURN_VARIANT* pValue | ||
140 | ); | ||
141 | static HRESULT InitializeUserLanguageID( | ||
142 | __in DWORD_PTR dwpData, | ||
143 | __inout BURN_VARIANT* pValue | ||
144 | ); | ||
145 | static HRESULT InitializeVariableString( | ||
146 | __in DWORD_PTR dwpData, | ||
147 | __inout BURN_VARIANT* pValue | ||
148 | ); | ||
149 | static HRESULT InitializeVariableNumeric( | ||
150 | __in DWORD_PTR dwpData, | ||
151 | __inout BURN_VARIANT* pValue | ||
152 | ); | ||
153 | static HRESULT InitializeVariableRegistryFolder( | ||
154 | __in DWORD_PTR dwpData, | ||
155 | __inout BURN_VARIANT* pValue | ||
156 | ); | ||
157 | static HRESULT InitializeVariable6432Folder( | ||
158 | __in DWORD_PTR dwpData, | ||
159 | __inout BURN_VARIANT* pValue | ||
160 | ); | ||
161 | static HRESULT InitializeVariableDate( | ||
162 | __in DWORD_PTR dwpData, | ||
163 | __inout BURN_VARIANT* pValue | ||
164 | ); | ||
165 | static HRESULT InitializeVariableInstallerName( | ||
166 | __in DWORD_PTR dwpData, | ||
167 | __inout BURN_VARIANT* pValue | ||
168 | ); | ||
169 | static HRESULT InitializeVariableInstallerVersion( | ||
170 | __in DWORD_PTR dwpData, | ||
171 | __inout BURN_VARIANT* pValue | ||
172 | ); | ||
173 | static HRESULT InitializeVariableVersion( | ||
174 | __in DWORD_PTR dwpData, | ||
175 | __inout BURN_VARIANT* pValue | ||
176 | ); | ||
177 | static HRESULT InitializeVariableLogonUser( | ||
178 | __in DWORD_PTR dwpData, | ||
179 | __inout BURN_VARIANT* pValue | ||
180 | ); | ||
181 | static HRESULT Get64bitFolderFromRegistry( | ||
182 | __in int nFolder, | ||
183 | __deref_out_z LPWSTR* psczPath | ||
184 | ); | ||
185 | |||
186 | |||
187 | // function definitions | ||
188 | |||
189 | extern "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 | |||
281 | LExit: | ||
282 | return hr; | ||
283 | } | ||
284 | |||
285 | extern "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 | |||
418 | LExit: | ||
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 | |||
430 | extern "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 | |||
451 | extern "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. | ||
492 | extern "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 | |||
517 | LExit: | ||
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. | ||
524 | extern "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 | |||
549 | LExit: | ||
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. | ||
556 | extern "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 | |||
581 | LExit: | ||
582 | ::LeaveCriticalSection(&pVariables->csAccess); | ||
583 | |||
584 | return hr; | ||
585 | } | ||
586 | |||
587 | extern "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 | |||
608 | LExit: | ||
609 | ::LeaveCriticalSection(&pVariables->csAccess); | ||
610 | |||
611 | return hr; | ||
612 | } | ||
613 | |||
614 | // The contents of psczValue may be sensitive, should keep encrypted and SecureZeroFree. | ||
615 | extern "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 | |||
655 | LExit: | ||
656 | ::LeaveCriticalSection(&pVariables->csAccess); | ||
657 | StrSecureZeroFreeString(scz); | ||
658 | |||
659 | return hr; | ||
660 | } | ||
661 | |||
662 | extern "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 | |||
678 | extern "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 | |||
694 | extern "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 | |||
710 | extern "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 | |||
726 | extern "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 | ||
736 | extern "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 | |||
746 | extern "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 | |||
756 | extern "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 | |||
805 | LExit: | ||
806 | ReleaseStr(pwzEscaped); | ||
807 | ReleaseStr(pwz); | ||
808 | return hr; | ||
809 | } | ||
810 | |||
811 | extern "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 | |||
899 | LExit: | ||
900 | ::LeaveCriticalSection(&pVariables->csAccess); | ||
901 | SecureZeroMemory(&ll, sizeof(ll)); | ||
902 | SecureZeroMemory(&qw, sizeof(qw)); | ||
903 | StrSecureZeroFreeString(scz); | ||
904 | |||
905 | return hr; | ||
906 | } | ||
907 | |||
908 | extern "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 | |||
1000 | LExit: | ||
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 | |||
1011 | extern "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 | |||
1031 | extern "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 | |||
1052 | extern "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 | |||
1073 | extern "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 | |||
1097 | extern "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 | |||
1120 | LExit: | ||
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. | ||
1130 | static 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 | |||
1306 | LExit: | ||
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 | |||
1346 | static 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 | |||
1376 | LExit: | ||
1377 | return hr; | ||
1378 | } | ||
1379 | |||
1380 | static 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 | |||
1409 | LExit: | ||
1410 | return hr; | ||
1411 | } | ||
1412 | |||
1413 | static 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 | |||
1452 | LExit: | ||
1453 | return hr; | ||
1454 | } | ||
1455 | |||
1456 | static 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 | |||
1509 | LExit: | ||
1510 | return hr; | ||
1511 | } | ||
1512 | |||
1513 | static 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 | |||
1608 | LExit: | ||
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 | |||
1619 | extern "C" typedef NTSTATUS (NTAPI *RTL_GET_VERSION)(_Out_ PRTL_OSVERSIONINFOEXW lpVersionInformation); | ||
1620 | |||
1621 | static 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 | |||
1682 | LExit: | ||
1683 | if (NULL != ntdll) | ||
1684 | { | ||
1685 | FreeLibrary(ntdll); | ||
1686 | } | ||
1687 | |||
1688 | return hr; | ||
1689 | } | ||
1690 | |||
1691 | static 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 | |||
1764 | LExit: | ||
1765 | return hr; | ||
1766 | } | ||
1767 | |||
1768 | static 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 | |||
1793 | LExit: | ||
1794 | return hr; | ||
1795 | } | ||
1796 | |||
1797 | static 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 | |||
1818 | LExit: | ||
1819 | return hr; | ||
1820 | } | ||
1821 | |||
1822 | static 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 | |||
1845 | LExit: | ||
1846 | return hr; | ||
1847 | } | ||
1848 | |||
1849 | static 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 | |||
1866 | LExit: | ||
1867 | ReleaseStr(sczPath); | ||
1868 | |||
1869 | return hr; | ||
1870 | } | ||
1871 | |||
1872 | static 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 | |||
1892 | LExit: | ||
1893 | return hr; | ||
1894 | } | ||
1895 | |||
1896 | static 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 | |||
1963 | LExit: | ||
1964 | return hr; | ||
1965 | } | ||
1966 | |||
1967 | static 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 | |||
1994 | LExit: | ||
1995 | return hr; | ||
1996 | } | ||
1997 | |||
1998 | static 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 | |||
2016 | LExit: | ||
2017 | return hr; | ||
2018 | } | ||
2019 | |||
2020 | static 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 | |||
2049 | LExit: | ||
2050 | if (fComInitialized) | ||
2051 | { | ||
2052 | ::CoUninitialize(); | ||
2053 | } | ||
2054 | |||
2055 | return hr; | ||
2056 | } | ||
2057 | |||
2058 | static 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 | |||
2071 | LExit: | ||
2072 | return hr; | ||
2073 | } | ||
2074 | |||
2075 | static 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 | |||
2088 | LExit: | ||
2089 | return hr; | ||
2090 | } | ||
2091 | |||
2092 | static 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 | |||
2105 | LExit: | ||
2106 | return hr; | ||
2107 | } | ||
2108 | |||
2109 | static 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 | |||
2121 | LExit: | ||
2122 | return hr; | ||
2123 | } | ||
2124 | |||
2125 | static 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 | |||
2137 | LExit: | ||
2138 | return hr; | ||
2139 | } | ||
2140 | |||
2141 | static 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 | |||
2167 | LExit: | ||
2168 | ReleaseStr(sczPath); | ||
2169 | |||
2170 | return hr; | ||
2171 | } | ||
2172 | |||
2173 | static 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 | |||
2203 | LExit: | ||
2204 | ReleaseStr(sczPath); | ||
2205 | |||
2206 | return hr; | ||
2207 | } | ||
2208 | |||
2209 | // Get the date in the same format as Windows Installer. | ||
2210 | static 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 | |||
2240 | LExit: | ||
2241 | ReleaseStr(sczDate); | ||
2242 | |||
2243 | return hr; | ||
2244 | } | ||
2245 | |||
2246 | static 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 | |||
2257 | LExit: | ||
2258 | return hr; | ||
2259 | } | ||
2260 | |||
2261 | static 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 | |||
2276 | LExit: | ||
2277 | ReleaseStr(sczVersion); | ||
2278 | |||
2279 | return hr; | ||
2280 | } | ||
2281 | |||
2282 | static 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 | |||
2293 | LExit: | ||
2294 | return hr; | ||
2295 | } | ||
2296 | |||
2297 | // Get the current user the same as Windows Installer. | ||
2298 | static 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 | |||
2316 | LExit: | ||
2317 | return hr; | ||
2318 | } | ||
2319 | |||
2320 | static 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 | |||
2340 | LExit: | ||
2341 | ReleaseRegKey(hkFolders); | ||
2342 | |||
2343 | return hr; | ||
2344 | } | ||
2345 | |||