main
cpp 362 lines 12.5 KB
Raw
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 // internal function declarations
7
8
9 // function definitions
10
11 extern "C" HRESULT PayloadsParseFromXml(
12 __in BURN_PAYLOADS* pPayloads,
13 __in_opt BURN_CONTAINERS* pContainers,
14 __in_opt BURN_PAYLOAD_GROUP* pLayoutPayloads,
15 __in IXMLDOMNode* pixnBundle
16 )
17 {
18 HRESULT hr = S_OK;
19 IXMLDOMNodeList* pixnNodes = NULL;
20 IXMLDOMNode* pixnNode = NULL;
21 DWORD cNodes = 0;
22 LPWSTR scz = NULL;
23 BOOL fChainPayload = pContainers && pLayoutPayloads; // These are required when parsing chain payloads.
24 BOOL fValidFileSize = FALSE;
25 size_t cByteOffset = fChainPayload ? offsetof(BURN_PAYLOAD, sczKey) : offsetof(BURN_PAYLOAD, sczSourcePath);
26 BOOL fXmlFound = FALSE;
27
28 // select payload nodes
29 hr = XmlSelectNodes(pixnBundle, L"Payload", &pixnNodes);
30 ExitOnFailure(hr, "Failed to select payload nodes.");
31
32 // get payload node count
33 hr = pixnNodes->get_length((long*)&cNodes);
34 ExitOnFailure(hr, "Failed to get payload node count.");
35
36 if (!cNodes)
37 {
38 ExitFunction();
39 }
40
41 // allocate memory for payloads
42 pPayloads->rgPayloads = (BURN_PAYLOAD*)MemAlloc(sizeof(BURN_PAYLOAD) * cNodes, TRUE);
43 ExitOnNull(pPayloads->rgPayloads, hr, E_OUTOFMEMORY, "Failed to allocate memory for payload structs.");
44
45 pPayloads->cPayloads = cNodes;
46
47 // create dictionary for payloads
48 hr = DictCreateWithEmbeddedKey(&pPayloads->sdhPayloads, pPayloads->cPayloads, reinterpret_cast<void**>(&pPayloads->rgPayloads), cByteOffset, DICT_FLAG_NONE);
49 ExitOnFailure(hr, "Failed to create dictionary for payloads.");
50
51 // parse payload elements
52 for (DWORD i = 0; i < cNodes; ++i)
53 {
54 BURN_PAYLOAD* pPayload = &pPayloads->rgPayloads[i];
55 fValidFileSize = FALSE;
56
57 hr = XmlNextElement(pixnNodes, &pixnNode, NULL);
58 ExitOnFailure(hr, "Failed to get next node.");
59
60 // @Id
61 hr = XmlGetAttributeEx(pixnNode, L"Id", &pPayload->sczKey);
62 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Id.");
63
64 // @FilePath
65 hr = XmlGetAttributeEx(pixnNode, L"FilePath", &pPayload->sczFilePath);
66 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @FilePath.");
67
68 // @SourcePath
69 hr = XmlGetAttributeEx(pixnNode, L"SourcePath", &pPayload->sczSourcePath);
70 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @SourcePath.");
71
72 if (!fChainPayload)
73 {
74 // All non-chain payloads are embedded in the UX container.
75 pPayload->packaging = BURN_PAYLOAD_PACKAGING_EMBEDDED;
76 }
77 else
78 {
79 // @Packaging
80 hr = XmlGetAttributeEx(pixnNode, L"Packaging", &scz);
81 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Packaging.");
82
83 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"embedded", -1))
84 {
85 pPayload->packaging = BURN_PAYLOAD_PACKAGING_EMBEDDED;
86 }
87 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"external", -1))
88 {
89 pPayload->packaging = BURN_PAYLOAD_PACKAGING_EXTERNAL;
90 }
91 else
92 {
93 ExitWithRootFailure(hr, E_INVALIDARG, "Invalid value for @Packaging: %ls", scz);
94 }
95
96 // @Container
97 hr = XmlGetAttributeEx(pixnNode, L"Container", &scz);
98 ExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get @Container.");
99
100 if (fXmlFound)
101 {
102 // find container
103 hr = ContainerFindById(pContainers, scz, &pPayload->pContainer);
104 ExitOnFailure(hr, "Failed to find container: %ls", scz);
105
106 pPayload->pContainer->cParsedPayloads += 1;
107 }
108 else if (BURN_PAYLOAD_PACKAGING_EMBEDDED == pPayload->packaging)
109 {
110 ExitWithRootFailure(hr, E_NOTFOUND, "@Container is required for embedded payload.");
111 }
112
113 // @LayoutOnly
114 hr = XmlGetYesNoAttribute(pixnNode, L"LayoutOnly", &pPayload->fLayoutOnly);
115 ExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get @LayoutOnly.");
116
117 // @DownloadUrl
118 hr = XmlGetAttributeEx(pixnNode, L"DownloadUrl", &pPayload->downloadSource.sczUrl);
119 ExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get @DownloadUrl.");
120
121 // @FileSize
122 hr = XmlGetAttributeEx(pixnNode, L"FileSize", &scz);
123 ExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get @FileSize.");
124
125 if (fXmlFound)
126 {
127 hr = StrStringToUInt64(scz, 0, &pPayload->qwFileSize);
128 ExitOnFailure(hr, "Failed to parse @FileSize.");
129
130 fValidFileSize = TRUE;
131 }
132
133 // @CertificateAuthorityKeyIdentifier
134 hr = XmlGetAttributeEx(pixnNode, L"CertificateRootPublicKeyIdentifier", &scz);
135 ExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get @CertificateRootPublicKeyIdentifier.");
136
137 if (fXmlFound)
138 {
139 hr = StrAllocHexDecode(scz, &pPayload->pbCertificateRootPublicKeyIdentifier, &pPayload->cbCertificateRootPublicKeyIdentifier);
140 ExitOnFailure(hr, "Failed to hex decode @CertificateRootPublicKeyIdentifier.");
141
142 pPayload->verification = BURN_PAYLOAD_VERIFICATION_AUTHENTICODE;
143 }
144
145 // @CertificateThumbprint
146 hr = XmlGetAttributeEx(pixnNode, L"CertificateRootThumbprint", &scz);
147 ExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get @CertificateRootThumbprint.");
148
149 if (fXmlFound)
150 {
151 hr = StrAllocHexDecode(scz, &pPayload->pbCertificateRootThumbprint, &pPayload->cbCertificateRootThumbprint);
152 ExitOnFailure(hr, "Failed to hex decode @CertificateRootThumbprint.");
153 }
154
155 // @Hash
156 hr = XmlGetAttributeEx(pixnNode, L"Hash", &scz);
157 ExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get @Hash.");
158
159 if (fXmlFound)
160 {
161 hr = StrAllocHexDecode(scz, &pPayload->pbHash, &pPayload->cbHash);
162 ExitOnFailure(hr, "Failed to hex decode the Payload/@Hash.");
163
164 if (BURN_PAYLOAD_VERIFICATION_NONE == pPayload->verification)
165 {
166 pPayload->verification = BURN_PAYLOAD_VERIFICATION_HASH;
167 }
168 }
169
170 if (BURN_PAYLOAD_VERIFICATION_NONE == pPayload->verification)
171 {
172 ExitWithRootFailure(hr, E_INVALIDDATA, "There was no verification information for payload: %ls", pPayload->sczKey);
173 }
174 else if (BURN_PAYLOAD_VERIFICATION_HASH == pPayload->verification && !fValidFileSize)
175 {
176 ExitWithRootFailure(hr, E_INVALIDDATA, "File size is required when verifying by hash for payload: %ls", pPayload->sczKey);
177 }
178
179 if (pPayload->fLayoutOnly)
180 {
181 hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pLayoutPayloads->rgItems), pLayoutPayloads->cItems + 1, sizeof(BURN_PAYLOAD_GROUP_ITEM), 5);
182 ExitOnFailure(hr, "Failed to allocate memory for layout payloads.");
183
184 pLayoutPayloads->rgItems[pLayoutPayloads->cItems].pPayload = pPayload;
185 ++pLayoutPayloads->cItems;
186
187 pLayoutPayloads->qwTotalSize += pPayload->qwFileSize;
188 }
189 }
190
191 hr = DictAddValue(pPayloads->sdhPayloads, pPayload);
192 ExitOnFailure(hr, "Failed to add payload to payloads dictionary.");
193
194 // prepare next iteration
195 ReleaseNullObject(pixnNode);
196 }
197
198 hr = S_OK;
199
200 if (pContainers && pContainers->cContainers)
201 {
202 for (DWORD i = 0; i < pPayloads->cPayloads; ++i)
203 {
204 BURN_PAYLOAD* pPayload = &pPayloads->rgPayloads[i];
205 BURN_CONTAINER* pContainer = pPayload->pContainer;
206
207 if (!pContainer)
208 {
209 continue;
210 }
211 else if (!pContainer->sdhPayloads)
212 {
213 hr = DictCreateWithEmbeddedKey(&pContainer->sdhPayloads, pContainer->cParsedPayloads, NULL, offsetof(BURN_PAYLOAD, sczSourcePath), DICT_FLAG_NONE);
214 ExitOnFailure(hr, "Failed to create dictionary for container payloads.");
215 }
216
217 hr = DictAddValue(pContainer->sdhPayloads, pPayload);
218 ExitOnFailure(hr, "Failed to add payload to container dictionary.");
219 }
220 }
221
222 LExit:
223 ReleaseObject(pixnNodes);
224 ReleaseObject(pixnNode);
225 ReleaseStr(scz);
226
227 return hr;
228 }
229
230 extern "C" void PayloadUninitialize(
231 __in BURN_PAYLOAD* pPayload
232 )
233 {
234 if (pPayload)
235 {
236 ReleaseStr(pPayload->sczKey);
237 ReleaseStr(pPayload->sczFilePath);
238 ReleaseMem(pPayload->pbHash);
239 ReleaseMem(pPayload->pbCertificateRootThumbprint);
240 ReleaseMem(pPayload->pbCertificateRootPublicKeyIdentifier);
241 ReleaseStr(pPayload->sczSourcePath);
242 ReleaseStr(pPayload->sczLocalFilePath);
243 ReleaseStr(pPayload->sczFailedLocalAcquisitionPath);
244 ReleaseStr(pPayload->downloadSource.sczUrl);
245 ReleaseStr(pPayload->downloadSource.sczUser);
246 ReleaseStr(pPayload->downloadSource.sczPassword);
247 ReleaseStr(pPayload->downloadSource.sczAuthorizationHeader);
248 ReleaseStr(pPayload->sczUnverifiedPath);
249 }
250 }
251
252 extern "C" void PayloadsUninitialize(
253 __in BURN_PAYLOADS* pPayloads
254 )
255 {
256 if (pPayloads->rgPayloads)
257 {
258 for (DWORD i = 0; i < pPayloads->cPayloads; ++i)
259 {
260 PayloadUninitialize(pPayloads->rgPayloads + i);
261 }
262 MemFree(pPayloads->rgPayloads);
263 }
264
265 ReleaseDict(pPayloads->sdhPayloads);
266
267 // clear struct
268 memset(pPayloads, 0, sizeof(BURN_PAYLOADS));
269 }
270
271 extern "C" HRESULT PayloadExtractUXContainer(
272 __in BURN_PAYLOADS* pPayloads,
273 __in BURN_CONTAINER_CONTEXT* pContainerContext,
274 __in_z LPCWSTR wzTargetDir
275 )
276 {
277 HRESULT hr = S_OK;
278 LPWSTR sczStreamName = NULL;
279 LPWSTR sczDirectory = NULL;
280 BURN_PAYLOAD* pPayload = NULL;
281
282 // extract all payloads
283 for (;;)
284 {
285 // get next stream
286 hr = ContainerNextStream(pContainerContext, &sczStreamName);
287 if (E_NOMOREITEMS == hr)
288 {
289 hr = S_OK;
290 break;
291 }
292 ExitOnFailure(hr, "Failed to get next stream.");
293
294 // find payload by stream name
295 hr = PayloadFindEmbeddedBySourcePath(pPayloads->sdhPayloads, sczStreamName, &pPayload);
296 ExitOnFailure(hr, "Failed to find embedded payload: %ls", sczStreamName);
297
298 // make file path
299 hr = PathConcatRelativeToFullyQualifiedBase(wzTargetDir, pPayload->sczFilePath, &pPayload->sczLocalFilePath);
300 ExitOnFailure(hr, "Failed to concat file paths.");
301
302 // extract file
303 hr = PathGetDirectory(pPayload->sczLocalFilePath, &sczDirectory);
304 ExitOnFailure(hr, "Failed to get directory portion of local file path");
305
306 hr = DirEnsureExists(sczDirectory, NULL);
307 ExitOnFailure(hr, "Failed to ensure directory exists");
308
309 hr = ContainerStreamToFile(pContainerContext, pPayload->sczLocalFilePath);
310 ExitOnFailure(hr, "Failed to extract file.");
311
312 // flag that the payload has been acquired
313 pPayload->state = BURN_PAYLOAD_STATE_ACQUIRED;
314 }
315
316 // locate any payloads that were not extracted
317 for (DWORD i = 0; i < pPayloads->cPayloads; ++i)
318 {
319 pPayload = &pPayloads->rgPayloads[i];
320
321 // if the payload has not been acquired
322 if (BURN_PAYLOAD_STATE_ACQUIRED > pPayload->state)
323 {
324 ExitWithRootFailure(hr, E_INVALIDDATA, "Payload was not found in container: %ls", pPayload->sczKey);
325 }
326 }
327
328 LExit:
329 ReleaseStr(sczStreamName);
330 ReleaseStr(sczDirectory);
331
332 return hr;
333 }
334
335 extern "C" HRESULT PayloadFindById(
336 __in BURN_PAYLOADS* pPayloads,
337 __in_z LPCWSTR wzId,
338 __out BURN_PAYLOAD** ppPayload
339 )
340 {
341 HRESULT hr = S_OK;
342
343 hr = DictGetValue(pPayloads->sdhPayloads, wzId, reinterpret_cast<void**>(ppPayload));
344
345 return hr;
346 }
347
348 extern "C" HRESULT PayloadFindEmbeddedBySourcePath(
349 __in STRINGDICT_HANDLE sdhPayloads,
350 __in_z LPCWSTR wzStreamName,
351 __out BURN_PAYLOAD** ppPayload
352 )
353 {
354 HRESULT hr = S_OK;
355
356 hr = DictGetValue(sdhPayloads, wzStreamName, reinterpret_cast<void**>(ppPayload));
357
358 return hr;
359 }
360
361
362 // internal function definitions