main
cpp 693 lines 21 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 static const LPCWSTR BA_PIPE_NAME_FORMAT_STRING = L"%ls.BA";
6 static const LPCWSTR ENGINE_PIPE_NAME_FORMAT_STRING = L"%ls.BAEngine";
7
8 // internal function declarations
9
10 static HRESULT CreateBootstrapperApplicationPipes(
11 __in_z LPCWSTR wzBasePipeName,
12 __out HANDLE* phBAPipe,
13 __out HANDLE* phBAEnginePipe
14 );
15 static 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 );
22 static void Disconnect(
23 __in BURN_USER_EXPERIENCE* pUserExperience
24 );
25 static int FilterResult(
26 __in DWORD dwAllowedResults,
27 __in int nResult
28 );
29 static HRESULT WaitForBootstrapperApplicationConnect(
30 __in HANDLE hBAProcess,
31 __in HANDLE hBAPipe,
32 __in HANDLE hBAEnginePipe,
33 __in_z LPCWSTR wzSecret
34 );
35 static HRESULT VerifyPipeSecret(
36 __in HANDLE hPipe,
37 __in_z LPCWSTR wzSecret
38 );
39
40
41 // function definitions
42
43 EXTERN_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
102 LExit:
103 ReleaseStr(sczSecondaryId);
104 ReleaseStr(sczPrimaryId);
105 ReleaseObject(pixnUserExperienceNode);
106
107 return hr;
108 }
109
110 EXTERN_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
127 EXTERN_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
178 LExit:
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
193 EXTERN_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
233 EXTERN_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
255 EXTERN_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
278 EXTERN_C HRESULT BootstrapperApplicationEnsureWorkingFolder(
279 __in BOOL fElevated,
280 __in BURN_CACHE* pCache,
281 __deref_out_z LPWSTR* psczUserExperienceWorkingFolder
282 )
283 {
284 HRESULT hr = S_OK;
285 LPWSTR sczWorkingFolder = NULL;
286
287 hr = CacheEnsureBaseWorkingFolder(fElevated, pCache, &sczWorkingFolder);
288 ExitOnFailure(hr, "Failed to create working folder.");
289
290 hr = StrAllocFormatted(psczUserExperienceWorkingFolder, L"%ls%ls\\", sczWorkingFolder, L".ba");
291 ExitOnFailure(hr, "Failed to calculate the bootstrapper application working path.");
292
293 hr = DirEnsureExists(*psczUserExperienceWorkingFolder, NULL);
294 ExitOnFailure(hr, "Failed create bootstrapper application working folder.");
295
296 LExit:
297 ReleaseStr(sczWorkingFolder);
298
299 return hr;
300 }
301
302
303 EXTERN_C HRESULT BootstrapperApplicationRemove(
304 __in BURN_USER_EXPERIENCE* pUserExperience
305 )
306 {
307 HRESULT hr = S_OK;
308
309 // Remove temporary UX directory
310 if (pUserExperience->sczTempDirectory)
311 {
312 hr = DirEnsureDeleteEx(pUserExperience->sczTempDirectory, DIR_DELETE_FILES | DIR_DELETE_RECURSE | DIR_DELETE_SCHEDULE);
313 TraceError(hr, "Could not delete bootstrapper application folder. Some files will be left in the temp folder.");
314 }
315
316 //LExit:
317 return hr;
318 }
319
320 EXTERN_C int BootstrapperApplicationSendError(
321 __in BURN_USER_EXPERIENCE* pUserExperience,
322 __in BOOTSTRAPPER_ERROR_TYPE errorType,
323 __in_z_opt LPCWSTR wzPackageId,
324 __in HRESULT hrCode,
325 __in_z_opt LPCWSTR wzError,
326 __in DWORD uiFlags,
327 __in int nRecommendation
328 )
329 {
330 int nResult = nRecommendation;
331 DWORD dwCode = HRESULT_CODE(hrCode);
332 LPWSTR sczError = NULL;
333
334 // If no error string was provided, try to get the error string from the HRESULT.
335 if (!wzError)
336 {
337 if (SUCCEEDED(StrAllocFromError(&sczError, hrCode, NULL)))
338 {
339 wzError = sczError;
340 }
341 }
342
343 BACallbackOnError(pUserExperience, errorType, wzPackageId, dwCode, wzError, uiFlags, 0, NULL, &nResult); // ignore return value.
344
345 ReleaseStr(sczError);
346 return nResult;
347 }
348
349 EXTERN_C void BootstrapperApplicationActivateEngine(
350 __in BURN_USER_EXPERIENCE* pUserExperience
351 )
352 {
353 ::EnterCriticalSection(&pUserExperience->csEngineActive);
354 AssertSz(!pUserExperience->fEngineActive, "Engine should have been deactivated before activating it.");
355 pUserExperience->fEngineActive = TRUE;
356 ::LeaveCriticalSection(&pUserExperience->csEngineActive);
357 }
358
359 EXTERN_C void BootstrapperApplicationDeactivateEngine(
360 __in BURN_USER_EXPERIENCE* pUserExperience
361 )
362 {
363 ::EnterCriticalSection(&pUserExperience->csEngineActive);
364 AssertSz(pUserExperience->fEngineActive, "Engine should have been active before deactivating it.");
365 pUserExperience->fEngineActive = FALSE;
366 ::LeaveCriticalSection(&pUserExperience->csEngineActive);
367 }
368
369 EXTERN_C HRESULT BootstrapperApplicationEnsureEngineInactive(
370 __in BURN_USER_EXPERIENCE* pUserExperience
371 )
372 {
373 // Make a slight optimization here by ignoring the critical section, because all callers should have needed to enter it for their operation anyway.
374 HRESULT hr = pUserExperience->fEngineActive ? HRESULT_FROM_WIN32(ERROR_BUSY) : S_OK;
375 ExitOnRootFailure(hr, "Engine is active, cannot proceed.");
376
377 LExit:
378 return hr;
379 }
380
381 EXTERN_C void BootstrapperApplicationExecuteReset(
382 __in BURN_USER_EXPERIENCE* pUserExperience
383 )
384 {
385 pUserExperience->hrApplyError = S_OK;
386 pUserExperience->hwndApply = NULL;
387 }
388
389 EXTERN_C void BootstrapperApplicationExecutePhaseComplete(
390 __in BURN_USER_EXPERIENCE* pUserExperience,
391 __in HRESULT hrResult
392 )
393 {
394 if (FAILED(hrResult))
395 {
396 pUserExperience->hrApplyError = hrResult;
397 }
398 }
399
400
401 // internal function definitions
402
403 static HRESULT CreateBootstrapperApplicationPipes(
404 __in_z LPCWSTR wzBasePipeName,
405 __out HANDLE* phBAPipe,
406 __out HANDLE* phBAEnginePipe
407 )
408 {
409 HRESULT hr = S_OK;
410 LPWSTR sczPipeName = NULL;
411 HANDLE hBAPipe = INVALID_HANDLE_VALUE;
412 HANDLE hBAEnginePipe = INVALID_HANDLE_VALUE;
413
414 // Create the bootstrapper application pipe.
415 hr = StrAllocFormatted(&sczPipeName, BA_PIPE_NAME_FORMAT_STRING, wzBasePipeName);
416 ExitOnFailure(hr, "Failed to allocate full name of bootstrapper pipe: %ls", wzBasePipeName);
417
418 hr = PipeCreate(sczPipeName, NULL, &hBAPipe);
419 ExitOnFailure(hr, "Failed to create cache pipe: %ls", sczPipeName);
420
421 // Create the bootstrapper application's engine pipe.
422 hr = StrAllocFormatted(&sczPipeName, ENGINE_PIPE_NAME_FORMAT_STRING, wzBasePipeName);
423 ExitOnFailure(hr, "Failed to allocate full name of bootstrapper application engine pipe: %ls", wzBasePipeName);
424
425 hr = PipeCreate(sczPipeName, NULL, &hBAEnginePipe);
426 ExitOnFailure(hr, "Failed to create cache pipe: %ls", sczPipeName);
427
428 *phBAEnginePipe = hBAEnginePipe;
429 hBAEnginePipe = INVALID_HANDLE_VALUE;
430
431 *phBAPipe = hBAPipe;
432 hBAPipe = INVALID_HANDLE_VALUE;
433
434 LExit:
435 ReleasePipeHandle(hBAEnginePipe);
436 ReleasePipeHandle(hBAPipe);
437
438 return hr;
439 }
440
441 static HRESULT CreateBootstrapperApplicationProcess(
442 __in_z LPCWSTR wzBootstrapperApplicationPath,
443 __in int nCmdShow,
444 __in_z LPCWSTR wzPipeName,
445 __in_z LPCWSTR wzSecret,
446 __out HANDLE* phProcess
447 )
448 {
449 HRESULT hr = S_OK;
450 LPWSTR sczParameters = NULL;
451 LPWSTR sczFullCommandLine = NULL;
452 PROCESS_INFORMATION pi = { };
453
454 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);
455 ExitOnFailure(hr, "Failed to allocate parameters for bootstrapper application process.");
456
457 hr = StrAllocFormattedSecure(&sczFullCommandLine, L"\"%ls\" %ls", wzBootstrapperApplicationPath, sczParameters);
458 ExitOnFailure(hr, "Failed to allocate full command-line for bootstrapper application process.");
459
460 hr = CoreCreateProcess(wzBootstrapperApplicationPath, sczFullCommandLine, FALSE, 0, NULL, static_cast<WORD>(nCmdShow), &pi);
461 ExitOnFailure(hr, "Failed to launch bootstrapper application process: %ls", sczFullCommandLine);
462
463 *phProcess = pi.hProcess;
464 pi.hProcess = NULL;
465
466 LExit:
467 ReleaseHandle(pi.hThread);
468 ReleaseHandle(pi.hProcess);
469 StrSecureZeroFreeString(sczFullCommandLine);
470 StrSecureZeroFreeString(sczParameters);
471
472 return hr;
473 }
474
475 static void Disconnect(
476 __in BURN_USER_EXPERIENCE* pUserExperience
477 )
478 {
479 if (PipeRpcInitialized(&pUserExperience->hBARpcPipe))
480 {
481 PipeWriteDisconnect(pUserExperience->hBARpcPipe.hPipe);
482
483 PipeRpcUninitiailize(&pUserExperience->hBARpcPipe);
484 }
485 }
486
487 static int FilterResult(
488 __in DWORD dwAllowedResults,
489 __in int nResult
490 )
491 {
492 if (IDNOACTION == nResult || IDERROR == nResult) // do nothing and errors pass through.
493 {
494 }
495 else
496 {
497 switch (dwAllowedResults)
498 {
499 case MB_OK:
500 nResult = IDOK;
501 break;
502
503 case MB_OKCANCEL:
504 if (IDOK == nResult || IDYES == nResult)
505 {
506 nResult = IDOK;
507 }
508 else if (IDCANCEL == nResult || IDABORT == nResult || IDNO == nResult)
509 {
510 nResult = IDCANCEL;
511 }
512 else
513 {
514 nResult = IDNOACTION;
515 }
516 break;
517
518 case MB_ABORTRETRYIGNORE:
519 if (IDCANCEL == nResult || IDABORT == nResult)
520 {
521 nResult = IDABORT;
522 }
523 else if (IDRETRY == nResult || IDTRYAGAIN == nResult)
524 {
525 nResult = IDRETRY;
526 }
527 else if (IDIGNORE == nResult)
528 {
529 nResult = IDIGNORE;
530 }
531 else
532 {
533 nResult = IDNOACTION;
534 }
535 break;
536
537 case MB_YESNO:
538 if (IDOK == nResult || IDYES == nResult)
539 {
540 nResult = IDYES;
541 }
542 else if (IDCANCEL == nResult || IDABORT == nResult || IDNO == nResult)
543 {
544 nResult = IDNO;
545 }
546 else
547 {
548 nResult = IDNOACTION;
549 }
550 break;
551
552 case MB_YESNOCANCEL:
553 if (IDOK == nResult || IDYES == nResult)
554 {
555 nResult = IDYES;
556 }
557 else if (IDNO == nResult)
558 {
559 nResult = IDNO;
560 }
561 else if (IDCANCEL == nResult || IDABORT == nResult)
562 {
563 nResult = IDCANCEL;
564 }
565 else
566 {
567 nResult = IDNOACTION;
568 }
569 break;
570
571 case MB_RETRYCANCEL:
572 if (IDRETRY == nResult || IDTRYAGAIN == nResult)
573 {
574 nResult = IDRETRY;
575 }
576 else if (IDCANCEL == nResult || IDABORT == nResult)
577 {
578 nResult = IDABORT;
579 }
580 else
581 {
582 nResult = IDNOACTION;
583 }
584 break;
585
586 case MB_CANCELTRYCONTINUE:
587 if (IDCANCEL == nResult || IDABORT == nResult)
588 {
589 nResult = IDABORT;
590 }
591 else if (IDRETRY == nResult || IDTRYAGAIN == nResult)
592 {
593 nResult = IDRETRY;
594 }
595 else if (IDCONTINUE == nResult || IDIGNORE == nResult)
596 {
597 nResult = IDCONTINUE;
598 }
599 else
600 {
601 nResult = IDNOACTION;
602 }
603 break;
604
605 case BURN_MB_RETRYTRYAGAIN: // custom return code.
606 if (IDRETRY != nResult && IDTRYAGAIN != nResult)
607 {
608 nResult = IDNOACTION;
609 }
610 break;
611
612 default:
613 AssertSz(FALSE, "Unknown allowed results.");
614 break;
615 }
616 }
617
618 return nResult;
619 }
620
621 static HRESULT WaitForBootstrapperApplicationConnect(
622 __in HANDLE hBAProcess,
623 __in HANDLE hBAPipe,
624 __in HANDLE hBAEnginePipe,
625 __in_z LPCWSTR wzSecret
626 )
627 {
628 HRESULT hr = S_OK;
629 HANDLE hPipes[2] = { hBAPipe, hBAEnginePipe };
630
631 for (DWORD i = 0; i < countof(hPipes); ++i)
632 {
633 HANDLE hPipe = hPipes[i];
634
635 hr = PipeServerWaitForClientConnect(hBAProcess, hPipe);
636 ExitOnFailure(hr, "Failed to wait for bootstrapper application to connect to pipe.");
637
638 hr = VerifyPipeSecret(hPipe, wzSecret);
639 ExitOnFailure(hr, "Failed to verify bootstrapper application pipe");
640 }
641
642 LExit:
643 return hr;
644 }
645
646 static HRESULT VerifyPipeSecret(
647 __in HANDLE hPipe,
648 __in_z LPCWSTR wzSecret
649 )
650 {
651 HRESULT hr = S_OK;
652 HRESULT hrResponse = S_OK;
653 LPWSTR sczVerificationSecret = NULL;
654 DWORD cbVerificationSecret = 0;
655
656 // Read the verification secret.
657 hr = FileReadHandle(hPipe, reinterpret_cast<LPBYTE>(&cbVerificationSecret), sizeof(cbVerificationSecret));
658 ExitOnFailure(hr, "Failed to read size of verification secret from bootstrapper application pipe.");
659
660 if (255 < cbVerificationSecret / sizeof(WCHAR))
661 {
662 hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
663 ExitOnRootFailure(hr, "Verification secret from bootstrapper application is too big.");
664 }
665
666 hr = StrAlloc(&sczVerificationSecret, cbVerificationSecret / sizeof(WCHAR) + 1);
667 ExitOnFailure(hr, "Failed to allocate buffer for bootstrapper application verification secret.");
668
669 FileReadHandle(hPipe, reinterpret_cast<LPBYTE>(sczVerificationSecret), cbVerificationSecret);
670 ExitOnFailure(hr, "Failed to read verification secret from bootstrapper application pipe.");
671
672 // Verify the secrets match.
673 if (CSTR_EQUAL != ::CompareStringOrdinal(sczVerificationSecret, -1, wzSecret, -1, FALSE))
674 {
675 hrResponse = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
676 }
677
678 // Send the response.
679 hr = FileWriteHandle(hPipe, reinterpret_cast<LPBYTE>(&hrResponse), sizeof(hrResponse));
680 ExitOnFailure(hr, "Failed to write response to pipe.");
681
682 if (FAILED(hrResponse))
683 {
684 hr = hrResponse;
685 ExitOnRootFailure(hr, "Verification secret from bootstrapper application does not match.");
686 }
687
688 LExit:
689
690 ReleaseStr(sczVerificationSecret);
691
692 return hr;
693 }