aboutsummaryrefslogtreecommitdiff
path: root/src/burn/engine/bootstrapperapplication.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/burn/engine/bootstrapperapplication.cpp')
-rw-r--r--src/burn/engine/bootstrapperapplication.cpp692
1 files changed, 692 insertions, 0 deletions
diff --git a/src/burn/engine/bootstrapperapplication.cpp b/src/burn/engine/bootstrapperapplication.cpp
new file mode 100644
index 00000000..402f7015
--- /dev/null
+++ b/src/burn/engine/bootstrapperapplication.cpp
@@ -0,0 +1,692 @@
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
5static const LPCWSTR BA_PIPE_NAME_FORMAT_STRING = L"%ls.BA";
6static const LPCWSTR ENGINE_PIPE_NAME_FORMAT_STRING = L"%ls.BAEngine";
7
8// internal function declarations
9
10static HRESULT CreateBootstrapperApplicationPipes(
11 __in_z LPCWSTR wzBasePipeName,
12 __out HANDLE* phBAPipe,
13 __out HANDLE* phBAEnginePipe
14);
15static HRESULT CreateBootstrapperApplicationProcess(
16 __in_z LPCWSTR wzBootstrapperApplicationPath,
17 __in int nCmdShow,
18 __in_z LPCWSTR wzPipeName,
19 __in_z LPCWSTR wzSecret,
20 __out HANDLE* phProcess
21);
22static void Disconnect(
23 __in BURN_USER_EXPERIENCE* pUserExperience
24);
25static int FilterResult(
26 __in DWORD dwAllowedResults,
27 __in int nResult
28 );
29static HRESULT WaitForBootstrapperApplicationConnect(
30 __in HANDLE hBAProcess,
31 __in HANDLE hBAPipe,
32 __in HANDLE hBAEnginePipe,
33 __in_z LPCWSTR wzSecret
34);
35static HRESULT VerifyPipeSecret(
36 __in HANDLE hPipe,
37 __in_z LPCWSTR wzSecret
38);
39
40
41// function definitions
42
43EXTERN_C HRESULT BootstrapperApplicationParseFromXml(
44 __in BURN_USER_EXPERIENCE* pUserExperience,
45 __in IXMLDOMNode* pixnBundle
46)
47{
48 HRESULT hr = S_OK;
49 IXMLDOMNode* pixnUserExperienceNode = NULL;
50 LPWSTR sczPrimaryId = NULL;
51 LPWSTR sczSecondaryId = NULL;
52 BOOL fFoundSecondary = FALSE;
53
54 // select UX node
55 hr = XmlSelectSingleNode(pixnBundle, L"UX", &pixnUserExperienceNode);
56 if (S_FALSE == hr)
57 {
58 hr = E_NOTFOUND;
59 }
60 ExitOnFailure(hr, "Failed to select user experience node.");
61
62 // @PrimaryPayloadId
63 hr = XmlGetAttributeEx(pixnUserExperienceNode, L"PrimaryPayloadId", &sczPrimaryId);
64 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @PrimaryPayloadId.");
65
66 // @SecondaryPayloadId
67 hr = XmlGetAttributeEx(pixnUserExperienceNode, L"SecondaryPayloadId", &sczSecondaryId);
68 ExitOnOptionalXmlQueryFailure(hr, fFoundSecondary, "Failed to get @SecondaryPayloadId.");
69
70 // parse payloads
71 hr = PayloadsParseFromXml(&pUserExperience->payloads, NULL, NULL, pixnUserExperienceNode);
72 ExitOnFailure(hr, "Failed to parse user experience payloads.");
73
74 // make sure we have at least one payload
75 if (0 == pUserExperience->payloads.cPayloads)
76 {
77 hr = E_UNEXPECTED;
78 ExitOnFailure(hr, "Too few UX payloads.");
79 }
80
81 // Find the primary and secondary bootstrapper application payloads.
82 for (DWORD i = 0; i < pUserExperience->payloads.cPayloads; ++i)
83 {
84 BURN_PAYLOAD* pPayload = pUserExperience->payloads.rgPayloads + i;
85
86 if (!pUserExperience->pPrimaryExePayload && CSTR_EQUAL == ::CompareStringOrdinal(pPayload->sczKey, -1, sczPrimaryId, -1, FALSE))
87 {
88 pUserExperience->pPrimaryExePayload = pPayload;
89 }
90 else if (fFoundSecondary && !pUserExperience->pSecondaryExePayload && CSTR_EQUAL == ::CompareStringOrdinal(pPayload->sczKey, -1, sczSecondaryId, -1, FALSE))
91 {
92 pUserExperience->pSecondaryExePayload = pPayload;
93 }
94 }
95
96 if (!pUserExperience->pPrimaryExePayload)
97 {
98 hr = E_UNEXPECTED;
99 ExitOnFailure(hr, "Failed to find primary bootstrapper application payload.");
100 }
101
102LExit:
103 ReleaseStr(sczSecondaryId);
104 ReleaseStr(sczPrimaryId);
105 ReleaseObject(pixnUserExperienceNode);
106
107 return hr;
108}
109
110EXTERN_C void BootstrapperApplicationUninitialize(
111 __in BURN_USER_EXPERIENCE* pUserExperience
112)
113{
114 if (pUserExperience->pEngineContext)
115 {
116 BAEngineFreeContext(pUserExperience->pEngineContext);
117 pUserExperience->pEngineContext = NULL;
118 }
119
120 ReleaseStr(pUserExperience->sczTempDirectory);
121 PayloadsUninitialize(&pUserExperience->payloads);
122
123 // clear struct
124 memset(pUserExperience, 0, sizeof(BURN_USER_EXPERIENCE));
125}
126
127EXTERN_C HRESULT BootstrapperApplicationStart(
128 __in BURN_ENGINE_STATE* pEngineState,
129 __in BOOL fSecondary
130)
131{
132 HRESULT hr = S_OK;
133 LPWSTR sczBasePipeName = NULL;
134 LPWSTR sczSecret = NULL;
135 HANDLE hBAPipe = INVALID_HANDLE_VALUE;
136 HANDLE hBAEnginePipe = INVALID_HANDLE_VALUE;
137 BAENGINE_CONTEXT* pEngineContext = NULL;
138
139 BURN_USER_EXPERIENCE* pUserExperience = &pEngineState->userExperience;
140 BOOTSTRAPPER_COMMAND* pCommand = &pEngineState->command;
141 LPCWSTR wzBootstrapperApplicationPath = fSecondary && pUserExperience->pSecondaryExePayload ? pUserExperience->pSecondaryExePayload->sczLocalFilePath : pUserExperience->pPrimaryExePayload->sczLocalFilePath;
142
143 if (!wzBootstrapperApplicationPath)
144 {
145 hr = E_UNEXPECTED;
146 ExitOnFailure(hr, "Failed to find bootstrapper application path.");
147 }
148
149 hr = BurnPipeCreateNameAndSecret(&sczBasePipeName, &sczSecret);
150 ExitOnFailure(hr, "Failed to create bootstrapper application pipename and secret");
151
152 hr = CreateBootstrapperApplicationPipes(sczBasePipeName, &hBAPipe, &hBAEnginePipe);
153 ExitOnFailure(hr, "Failed to create bootstrapper application pipes");
154
155 hr = CreateBootstrapperApplicationProcess(wzBootstrapperApplicationPath, pCommand->nCmdShow, sczBasePipeName, sczSecret, &pUserExperience->hBAProcess);
156 ExitOnFailure(hr, "Failed to create bootstrapper application process: %ls", wzBootstrapperApplicationPath);
157
158 hr = WaitForBootstrapperApplicationConnect(pUserExperience->hBAProcess, hBAPipe, hBAEnginePipe, sczSecret);
159 ExitOnFailure(hr, "Failed while waiting for bootstrapper application to connect.");
160
161 hr = BAEngineCreateContext(pEngineState, &pEngineContext);
162 ExitOnFailure(hr, "Failed to create bootstrapper application engine context.");
163
164 pUserExperience->pEngineContext = pEngineContext;
165 pEngineContext = NULL;
166
167 PipeRpcInitialize(&pUserExperience->hBARpcPipe, hBAPipe, TRUE);
168 hBAPipe = INVALID_HANDLE_VALUE;
169
170 hr = BAEngineStartListening(pUserExperience->pEngineContext, hBAEnginePipe);
171 ExitOnFailure(hr, "Failed to start listening to bootstrapper application engine pipe.");
172
173 hBAEnginePipe = INVALID_HANDLE_VALUE;
174
175 hr = BACallbackOnCreate(pUserExperience, pCommand);
176 ExitOnFailure(hr, "Failed to create bootstrapper application");
177
178LExit:
179 if (pEngineContext)
180 {
181 BAEngineFreeContext(pEngineContext);
182 pEngineContext = NULL;
183 }
184
185 ReleasePipeHandle(hBAEnginePipe);
186 ReleasePipeHandle(hBAPipe);
187 ReleaseStr(sczSecret);
188 ReleaseStr(sczBasePipeName);
189
190 return hr;
191}
192
193EXTERN_C HRESULT BootstrapperApplicationStop(
194 __in BURN_USER_EXPERIENCE* pUserExperience,
195 __inout BOOL* pfReload
196)
197{
198 HRESULT hr = S_OK;
199 DWORD dwExitCode = ERROR_SUCCESS;
200
201 BACallbackOnDestroy(pUserExperience, *pfReload);
202
203 Disconnect(pUserExperience);
204
205 if (pUserExperience->pEngineContext)
206 {
207 BAEngineStopListening(pUserExperience->pEngineContext);
208 }
209
210 if (pUserExperience->hBAProcess)
211 {
212 hr = AppWaitForSingleObject(pUserExperience->hBAProcess, INFINITE);
213
214 ::GetExitCodeProcess(pUserExperience->hBAProcess, &dwExitCode);
215
216 ReleaseHandle(pUserExperience->hBAProcess);
217 }
218
219 // If the bootstrapper application process has already requested to reload, no need
220 // to check any further. But if the bootstrapper application process exited
221 // with anything but success then fallback to the other bootstrapper application.
222 // This should enable bootstrapper applications that fail to start due to missing
223 // prerequisites to fallback to the prerequisite bootstrapper application to install
224 // the necessary prerequisites.
225 if (!*pfReload)
226 {
227 *pfReload = (ERROR_SUCCESS != dwExitCode);
228 }
229
230 return hr;
231}
232
233EXTERN_C int BootstrapperApplicationCheckExecuteResult(
234 __in BURN_USER_EXPERIENCE* pUserExperience,
235 __in BOOL fRollback,
236 __in DWORD dwAllowedResults,
237 __in int nResult
238 )
239{
240 // Do not allow canceling while rolling back.
241 if (fRollback && (IDCANCEL == nResult || IDABORT == nResult))
242 {
243 nResult = IDNOACTION;
244 }
245 else if (FAILED(pUserExperience->hrApplyError) && !fRollback) // if we failed cancel except not during rollback.
246 {
247 nResult = IDCANCEL;
248 }
249
250 nResult = FilterResult(dwAllowedResults, nResult);
251
252 return nResult;
253}
254
255EXTERN_C HRESULT BootstrapperApplicationInterpretExecuteResult(
256 __in BURN_USER_EXPERIENCE* pUserExperience,
257 __in BOOL fRollback,
258 __in DWORD dwAllowedResults,
259 __in int nResult
260 )
261{
262 HRESULT hr = S_OK;
263
264 // If we failed return that error unless this is rollback which should roll on.
265 if (FAILED(pUserExperience->hrApplyError) && !fRollback)
266 {
267 hr = pUserExperience->hrApplyError;
268 }
269 else
270 {
271 int nCheckedResult = BootstrapperApplicationCheckExecuteResult(pUserExperience, fRollback, dwAllowedResults, nResult);
272 hr = IDOK == nCheckedResult || IDNOACTION == nCheckedResult ? S_OK : IDCANCEL == nCheckedResult || IDABORT == nCheckedResult ? HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT) : HRESULT_FROM_WIN32(ERROR_INSTALL_FAILURE);
273 }
274
275 return hr;
276}
277
278EXTERN_C HRESULT BootstrapperApplicationEnsureWorkingFolder(
279 __in BURN_CACHE* pCache,
280 __deref_out_z LPWSTR* psczUserExperienceWorkingFolder
281 )
282{
283 HRESULT hr = S_OK;
284 LPWSTR sczWorkingFolder = NULL;
285
286 hr = CacheEnsureBaseWorkingFolder(pCache, &sczWorkingFolder);
287 ExitOnFailure(hr, "Failed to create working folder.");
288
289 hr = StrAllocFormatted(psczUserExperienceWorkingFolder, L"%ls%ls\\", sczWorkingFolder, L".ba");
290 ExitOnFailure(hr, "Failed to calculate the bootstrapper application working path.");
291
292 hr = DirEnsureExists(*psczUserExperienceWorkingFolder, NULL);
293 ExitOnFailure(hr, "Failed create bootstrapper application working folder.");
294
295LExit:
296 ReleaseStr(sczWorkingFolder);
297
298 return hr;
299}
300
301
302EXTERN_C HRESULT BootstrapperApplicationRemove(
303 __in BURN_USER_EXPERIENCE* pUserExperience
304 )
305{
306 HRESULT hr = S_OK;
307
308 // Remove temporary UX directory
309 if (pUserExperience->sczTempDirectory)
310 {
311 hr = DirEnsureDeleteEx(pUserExperience->sczTempDirectory, DIR_DELETE_FILES | DIR_DELETE_RECURSE | DIR_DELETE_SCHEDULE);
312 TraceError(hr, "Could not delete bootstrapper application folder. Some files will be left in the temp folder.");
313 }
314
315//LExit:
316 return hr;
317}
318
319EXTERN_C int BootstrapperApplicationSendError(
320 __in BURN_USER_EXPERIENCE* pUserExperience,
321 __in BOOTSTRAPPER_ERROR_TYPE errorType,
322 __in_z_opt LPCWSTR wzPackageId,
323 __in HRESULT hrCode,
324 __in_z_opt LPCWSTR wzError,
325 __in DWORD uiFlags,
326 __in int nRecommendation
327 )
328{
329 int nResult = nRecommendation;
330 DWORD dwCode = HRESULT_CODE(hrCode);
331 LPWSTR sczError = NULL;
332
333 // If no error string was provided, try to get the error string from the HRESULT.
334 if (!wzError)
335 {
336 if (SUCCEEDED(StrAllocFromError(&sczError, hrCode, NULL)))
337 {
338 wzError = sczError;
339 }
340 }
341
342 BACallbackOnError(pUserExperience, errorType, wzPackageId, dwCode, wzError, uiFlags, 0, NULL, &nResult); // ignore return value.
343
344 ReleaseStr(sczError);
345 return nResult;
346}
347
348EXTERN_C void BootstrapperApplicationActivateEngine(
349 __in BURN_USER_EXPERIENCE* pUserExperience
350 )
351{
352 ::EnterCriticalSection(&pUserExperience->csEngineActive);
353 AssertSz(!pUserExperience->fEngineActive, "Engine should have been deactivated before activating it.");
354 pUserExperience->fEngineActive = TRUE;
355 ::LeaveCriticalSection(&pUserExperience->csEngineActive);
356}
357
358EXTERN_C void BootstrapperApplicationDeactivateEngine(
359 __in BURN_USER_EXPERIENCE* pUserExperience
360 )
361{
362 ::EnterCriticalSection(&pUserExperience->csEngineActive);
363 AssertSz(pUserExperience->fEngineActive, "Engine should have been active before deactivating it.");
364 pUserExperience->fEngineActive = FALSE;
365 ::LeaveCriticalSection(&pUserExperience->csEngineActive);
366}
367
368EXTERN_C HRESULT BootstrapperApplicationEnsureEngineInactive(
369 __in BURN_USER_EXPERIENCE* pUserExperience
370 )
371{
372 // Make a slight optimization here by ignoring the critical section, because all callers should have needed to enter it for their operation anyway.
373 HRESULT hr = pUserExperience->fEngineActive ? HRESULT_FROM_WIN32(ERROR_BUSY) : S_OK;
374 ExitOnRootFailure(hr, "Engine is active, cannot proceed.");
375
376LExit:
377 return hr;
378}
379
380EXTERN_C void BootstrapperApplicationExecuteReset(
381 __in BURN_USER_EXPERIENCE* pUserExperience
382 )
383{
384 pUserExperience->hrApplyError = S_OK;
385 pUserExperience->hwndApply = NULL;
386}
387
388EXTERN_C void BootstrapperApplicationExecutePhaseComplete(
389 __in BURN_USER_EXPERIENCE* pUserExperience,
390 __in HRESULT hrResult
391 )
392{
393 if (FAILED(hrResult))
394 {
395 pUserExperience->hrApplyError = hrResult;
396 }
397}
398
399
400// internal function definitions
401
402static HRESULT CreateBootstrapperApplicationPipes(
403 __in_z LPCWSTR wzBasePipeName,
404 __out HANDLE* phBAPipe,
405 __out HANDLE* phBAEnginePipe
406 )
407{
408 HRESULT hr = S_OK;
409 LPWSTR sczPipeName = NULL;
410 HANDLE hBAPipe = INVALID_HANDLE_VALUE;
411 HANDLE hBAEnginePipe = INVALID_HANDLE_VALUE;
412
413 // Create the bootstrapper application pipe.
414 hr = StrAllocFormatted(&sczPipeName, BA_PIPE_NAME_FORMAT_STRING, wzBasePipeName);
415 ExitOnFailure(hr, "Failed to allocate full name of bootstrapper pipe: %ls", wzBasePipeName);
416
417 hr = PipeCreate(sczPipeName, NULL, &hBAPipe);
418 ExitOnFailure(hr, "Failed to create cache pipe: %ls", sczPipeName);
419
420 // Create the bootstrapper application's engine pipe.
421 hr = StrAllocFormatted(&sczPipeName, ENGINE_PIPE_NAME_FORMAT_STRING, wzBasePipeName);
422 ExitOnFailure(hr, "Failed to allocate full name of bootstrapper application engine pipe: %ls", wzBasePipeName);
423
424 hr = PipeCreate(sczPipeName, NULL, &hBAEnginePipe);
425 ExitOnFailure(hr, "Failed to create cache pipe: %ls", sczPipeName);
426
427 *phBAEnginePipe = hBAEnginePipe;
428 hBAEnginePipe = INVALID_HANDLE_VALUE;
429
430 *phBAPipe = hBAPipe;
431 hBAPipe = INVALID_HANDLE_VALUE;
432
433LExit:
434 ReleasePipeHandle(hBAEnginePipe);
435 ReleasePipeHandle(hBAPipe);
436
437 return hr;
438}
439
440static HRESULT CreateBootstrapperApplicationProcess(
441 __in_z LPCWSTR wzBootstrapperApplicationPath,
442 __in int nCmdShow,
443 __in_z LPCWSTR wzPipeName,
444 __in_z LPCWSTR wzSecret,
445 __out HANDLE* phProcess
446)
447{
448 HRESULT hr = S_OK;
449 LPWSTR sczParameters = NULL;
450 LPWSTR sczFullCommandLine = NULL;
451 PROCESS_INFORMATION pi = { };
452
453 hr = StrAllocFormatted(&sczParameters, L"-%ls %llu -%ls %ls %ls", BOOTSTRAPPER_APPLICATION_COMMANDLINE_SWITCH_API_VERSION, BOOTSTRAPPER_APPLICATION_API_VERSION, BOOTSTRAPPER_APPLICATION_COMMANDLINE_SWITCH_PIPE_NAME, wzPipeName, wzSecret);
454 ExitOnFailure(hr, "Failed to allocate parameters for bootstrapper application process.");
455
456 hr = StrAllocFormattedSecure(&sczFullCommandLine, L"\"%ls\" %ls", wzBootstrapperApplicationPath, sczParameters);
457 ExitOnFailure(hr, "Failed to allocate full command-line for bootstrapper application process.");
458
459 hr = CoreCreateProcess(wzBootstrapperApplicationPath, sczFullCommandLine, FALSE, 0, NULL, static_cast<WORD>(nCmdShow), &pi);
460 ExitOnFailure(hr, "Failed to launch bootstrapper application process: %ls", sczFullCommandLine);
461
462 *phProcess = pi.hProcess;
463 pi.hProcess = NULL;
464
465LExit:
466 ReleaseHandle(pi.hThread);
467 ReleaseHandle(pi.hProcess);
468 StrSecureZeroFreeString(sczFullCommandLine);
469 StrSecureZeroFreeString(sczParameters);
470
471 return hr;
472}
473
474static void Disconnect(
475 __in BURN_USER_EXPERIENCE* pUserExperience
476)
477{
478 if (PipeRpcInitialized(&pUserExperience->hBARpcPipe))
479 {
480 PipeWriteDisconnect(pUserExperience->hBARpcPipe.hPipe);
481
482 PipeRpcUninitiailize(&pUserExperience->hBARpcPipe);
483 }
484}
485
486static int FilterResult(
487 __in DWORD dwAllowedResults,
488 __in int nResult
489 )
490{
491 if (IDNOACTION == nResult || IDERROR == nResult) // do nothing and errors pass through.
492 {
493 }
494 else
495 {
496 switch (dwAllowedResults)
497 {
498 case MB_OK:
499 nResult = IDOK;
500 break;
501
502 case MB_OKCANCEL:
503 if (IDOK == nResult || IDYES == nResult)
504 {
505 nResult = IDOK;
506 }
507 else if (IDCANCEL == nResult || IDABORT == nResult || IDNO == nResult)
508 {
509 nResult = IDCANCEL;
510 }
511 else
512 {
513 nResult = IDNOACTION;
514 }
515 break;
516
517 case MB_ABORTRETRYIGNORE:
518 if (IDCANCEL == nResult || IDABORT == nResult)
519 {
520 nResult = IDABORT;
521 }
522 else if (IDRETRY == nResult || IDTRYAGAIN == nResult)
523 {
524 nResult = IDRETRY;
525 }
526 else if (IDIGNORE == nResult)
527 {
528 nResult = IDIGNORE;
529 }
530 else
531 {
532 nResult = IDNOACTION;
533 }
534 break;
535
536 case MB_YESNO:
537 if (IDOK == nResult || IDYES == nResult)
538 {
539 nResult = IDYES;
540 }
541 else if (IDCANCEL == nResult || IDABORT == nResult || IDNO == nResult)
542 {
543 nResult = IDNO;
544 }
545 else
546 {
547 nResult = IDNOACTION;
548 }
549 break;
550
551 case MB_YESNOCANCEL:
552 if (IDOK == nResult || IDYES == nResult)
553 {
554 nResult = IDYES;
555 }
556 else if (IDNO == nResult)
557 {
558 nResult = IDNO;
559 }
560 else if (IDCANCEL == nResult || IDABORT == nResult)
561 {
562 nResult = IDCANCEL;
563 }
564 else
565 {
566 nResult = IDNOACTION;
567 }
568 break;
569
570 case MB_RETRYCANCEL:
571 if (IDRETRY == nResult || IDTRYAGAIN == nResult)
572 {
573 nResult = IDRETRY;
574 }
575 else if (IDCANCEL == nResult || IDABORT == nResult)
576 {
577 nResult = IDABORT;
578 }
579 else
580 {
581 nResult = IDNOACTION;
582 }
583 break;
584
585 case MB_CANCELTRYCONTINUE:
586 if (IDCANCEL == nResult || IDABORT == nResult)
587 {
588 nResult = IDABORT;
589 }
590 else if (IDRETRY == nResult || IDTRYAGAIN == nResult)
591 {
592 nResult = IDRETRY;
593 }
594 else if (IDCONTINUE == nResult || IDIGNORE == nResult)
595 {
596 nResult = IDCONTINUE;
597 }
598 else
599 {
600 nResult = IDNOACTION;
601 }
602 break;
603
604 case BURN_MB_RETRYTRYAGAIN: // custom return code.
605 if (IDRETRY != nResult && IDTRYAGAIN != nResult)
606 {
607 nResult = IDNOACTION;
608 }
609 break;
610
611 default:
612 AssertSz(FALSE, "Unknown allowed results.");
613 break;
614 }
615 }
616
617 return nResult;
618}
619
620static HRESULT WaitForBootstrapperApplicationConnect(
621 __in HANDLE hBAProcess,
622 __in HANDLE hBAPipe,
623 __in HANDLE hBAEnginePipe,
624 __in_z LPCWSTR wzSecret
625)
626{
627 HRESULT hr = S_OK;
628 HANDLE hPipes[2] = { hBAPipe, hBAEnginePipe };
629
630 for (DWORD i = 0; i < countof(hPipes); ++i)
631 {
632 HANDLE hPipe = hPipes[i];
633
634 hr = PipeServerWaitForClientConnect(hBAProcess, hPipe);
635 ExitOnFailure(hr, "Failed to wait for bootstrapper application to connect to pipe.");
636
637 hr = VerifyPipeSecret(hPipe, wzSecret);
638 ExitOnFailure(hr, "Failed to verify bootstrapper application pipe");
639 }
640
641LExit:
642 return hr;
643}
644
645static HRESULT VerifyPipeSecret(
646 __in HANDLE hPipe,
647 __in_z LPCWSTR wzSecret
648)
649{
650 HRESULT hr = S_OK;
651 HRESULT hrResponse = S_OK;
652 LPWSTR sczVerificationSecret = NULL;
653 DWORD cbVerificationSecret = 0;
654
655 // Read the verification secret.
656 hr = FileReadHandle(hPipe, reinterpret_cast<LPBYTE>(&cbVerificationSecret), sizeof(cbVerificationSecret));
657 ExitOnFailure(hr, "Failed to read size of verification secret from bootstrapper application pipe.");
658
659 if (255 < cbVerificationSecret / sizeof(WCHAR))
660 {
661 hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
662 ExitOnRootFailure(hr, "Verification secret from bootstrapper application is too big.");
663 }
664
665 hr = StrAlloc(&sczVerificationSecret, cbVerificationSecret / sizeof(WCHAR) + 1);
666 ExitOnFailure(hr, "Failed to allocate buffer for bootstrapper application verification secret.");
667
668 FileReadHandle(hPipe, reinterpret_cast<LPBYTE>(sczVerificationSecret), cbVerificationSecret);
669 ExitOnFailure(hr, "Failed to read verification secret from bootstrapper application pipe.");
670
671 // Verify the secrets match.
672 if (CSTR_EQUAL != ::CompareStringOrdinal(sczVerificationSecret, -1, wzSecret, -1, FALSE))
673 {
674 hrResponse = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
675 }
676
677 // Send the response.
678 hr = FileWriteHandle(hPipe, reinterpret_cast<LPBYTE>(&hrResponse), sizeof(hrResponse));
679 ExitOnFailure(hr, "Failed to write response to pipe.");
680
681 if (FAILED(hrResponse))
682 {
683 hr = hrResponse;
684 ExitOnRootFailure(hr, "Verification secret from bootstrapper application does not match.");
685 }
686
687LExit:
688
689 ReleaseStr(sczVerificationSecret);
690
691 return hr;
692}