summaryrefslogtreecommitdiff
path: root/src/burn/test/BurnUnitTest/ElevationTest.cpp
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2021-04-22 17:06:54 -0700
committerRob Mensching <rob@firegiant.com>2021-04-29 16:36:06 -0700
commitaf10c45d7b3a44af0b461a557847fe03263dcc10 (patch)
tree6a5c1532304782c36ffe4200b38f3afb76789a43 /src/burn/test/BurnUnitTest/ElevationTest.cpp
parent9c2aed97299fb96aeee3f1471ce40225437aaecf (diff)
downloadwix-af10c45d7b3a44af0b461a557847fe03263dcc10.tar.gz
wix-af10c45d7b3a44af0b461a557847fe03263dcc10.tar.bz2
wix-af10c45d7b3a44af0b461a557847fe03263dcc10.zip
Move burn into burn
Diffstat (limited to 'src/burn/test/BurnUnitTest/ElevationTest.cpp')
-rw-r--r--src/burn/test/BurnUnitTest/ElevationTest.cpp221
1 files changed, 221 insertions, 0 deletions
diff --git a/src/burn/test/BurnUnitTest/ElevationTest.cpp b/src/burn/test/BurnUnitTest/ElevationTest.cpp
new file mode 100644
index 00000000..3d144128
--- /dev/null
+++ b/src/burn/test/BurnUnitTest/ElevationTest.cpp
@@ -0,0 +1,221 @@
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
6const DWORD TEST_CHILD_SENT_MESSAGE_ID = 0xFFFE;
7const DWORD TEST_PARENT_SENT_MESSAGE_ID = 0xFFFF;
8const HRESULT S_TEST_SUCCEEDED = 0x3133;
9const char TEST_MESSAGE_DATA[] = "{94949868-7EAE-4ac5-BEAC-AFCA2821DE01}";
10
11
12static BOOL STDAPICALLTYPE ElevateTest_ShellExecuteExW(
13 __inout LPSHELLEXECUTEINFOW lpExecInfo
14 );
15static DWORD CALLBACK ElevateTest_ThreadProc(
16 __in LPVOID lpThreadParameter
17 );
18static HRESULT ProcessParentMessages(
19 __in BURN_PIPE_MESSAGE* pMsg,
20 __in_opt LPVOID pvContext,
21 __out DWORD* pdwResult
22 );
23static HRESULT ProcessChildMessages(
24 __in BURN_PIPE_MESSAGE* pMsg,
25 __in_opt LPVOID pvContext,
26 __out DWORD* pdwResult
27 );
28
29namespace Microsoft
30{
31namespace Tools
32{
33namespace WindowsInstallerXml
34{
35namespace Test
36{
37namespace Bootstrapper
38{
39 using namespace System;
40 using namespace System::IO;
41 using namespace System::Threading;
42 using namespace Xunit;
43
44 public ref class ElevationTest : BurnUnitTest
45 {
46 public:
47 ElevationTest(BurnTestFixture^ fixture) : BurnUnitTest(fixture)
48 {
49 }
50
51 [Fact]
52 void ElevateTest()
53 {
54 HRESULT hr = S_OK;
55 BURN_PIPE_CONNECTION connection = { };
56 HANDLE hEvent = NULL;
57 DWORD dwResult = S_OK;
58 try
59 {
60 ShelFunctionOverride(ElevateTest_ShellExecuteExW);
61
62 PipeConnectionInitialize(&connection);
63
64 //
65 // per-user side setup
66 //
67 hr = PipeCreateNameAndSecret(&connection.sczName, &connection.sczSecret);
68 TestThrowOnFailure(hr, L"Failed to create connection name and secret.");
69
70 hr = PipeCreatePipes(&connection, TRUE, &hEvent);
71 TestThrowOnFailure(hr, L"Failed to create pipes.");
72
73 hr = PipeLaunchChildProcess(L"tests\\ignore\\this\\path\\to\\burn.exe", &connection, TRUE, NULL);
74 TestThrowOnFailure(hr, L"Failed to create elevated process.");
75
76 hr = PipeWaitForChildConnect(&connection);
77 TestThrowOnFailure(hr, L"Failed to wait for child process to connect.");
78
79 // post execute message
80 hr = PipeSendMessage(connection.hPipe, TEST_PARENT_SENT_MESSAGE_ID, NULL, 0, ProcessParentMessages, NULL, &dwResult);
81 TestThrowOnFailure(hr, "Failed to post execute message to per-machine process.");
82
83 //
84 // initiate termination
85 //
86 hr = PipeTerminateChildProcess(&connection, 666, FALSE);
87 TestThrowOnFailure(hr, L"Failed to terminate elevated process.");
88
89 // check flags
90 Assert::Equal(S_TEST_SUCCEEDED, (HRESULT)dwResult);
91 }
92 finally
93 {
94 PipeConnectionUninitialize(&connection);
95 ReleaseHandle(hEvent);
96 }
97 }
98 };
99}
100}
101}
102}
103}
104
105
106static BOOL STDAPICALLTYPE ElevateTest_ShellExecuteExW(
107 __inout LPSHELLEXECUTEINFOW lpExecInfo
108 )
109{
110 HRESULT hr = S_OK;
111 LPWSTR scz = NULL;
112
113 hr = StrAllocString(&scz, lpExecInfo->lpParameters, 0);
114 ExitOnFailure(hr, "Failed to copy arguments.");
115
116 // Pretend this thread is the elevated process.
117 lpExecInfo->hProcess = ::CreateThread(NULL, 0, ElevateTest_ThreadProc, scz, 0, NULL);
118 ExitOnNullWithLastError(lpExecInfo->hProcess, hr, "Failed to create thread.");
119 scz = NULL;
120
121LExit:
122 ReleaseStr(scz);
123
124 return SUCCEEDED(hr);
125}
126
127static DWORD CALLBACK ElevateTest_ThreadProc(
128 __in LPVOID lpThreadParameter
129 )
130{
131 HRESULT hr = S_OK;
132 LPWSTR sczArguments = (LPWSTR)lpThreadParameter;
133 BURN_PIPE_CONNECTION connection = { };
134 BURN_PIPE_RESULT result = { };
135
136 PipeConnectionInitialize(&connection);
137
138 StrAlloc(&connection.sczName, MAX_PATH);
139 StrAlloc(&connection.sczSecret, MAX_PATH);
140
141 // parse command line arguments
142 if (3 != swscanf_s(sczArguments, L"-q -burn.elevated %s %s %u", connection.sczName, MAX_PATH, connection.sczSecret, MAX_PATH, &connection.dwProcessId))
143 {
144 hr = E_INVALIDARG;
145 ExitOnFailure(hr, "Failed to parse argument string.");
146 }
147
148 // set up connection with per-user process
149 hr = PipeChildConnect(&connection, TRUE);
150 ExitOnFailure(hr, "Failed to connect to per-user process.");
151
152 // pump messages
153 hr = PipePumpMessages(connection.hPipe, ProcessChildMessages, static_cast<LPVOID>(connection.hPipe), &result);
154 ExitOnFailure(hr, "Failed while pumping messages in child 'process'.");
155
156LExit:
157 PipeConnectionUninitialize(&connection);
158 ReleaseStr(sczArguments);
159
160 return FAILED(hr) ? (DWORD)hr : result.dwResult;
161}
162
163static HRESULT ProcessParentMessages(
164 __in BURN_PIPE_MESSAGE* pMsg,
165 __in_opt LPVOID /*pvContext*/,
166 __out DWORD* pdwResult
167 )
168{
169 HRESULT hr = S_OK;
170 HRESULT hrResult = E_INVALIDDATA;
171
172 // Process the message.
173 switch (pMsg->dwMessage)
174 {
175 case TEST_CHILD_SENT_MESSAGE_ID:
176 if (sizeof(TEST_MESSAGE_DATA) == pMsg->cbData && 0 == memcmp(TEST_MESSAGE_DATA, pMsg->pvData, sizeof(TEST_MESSAGE_DATA)))
177 {
178 hrResult = S_TEST_SUCCEEDED;
179 }
180 break;
181
182 default:
183 hr = E_INVALIDARG;
184 ExitOnRootFailure(hr, "Unexpected elevated message sent to parent process, msg: %u", pMsg->dwMessage);
185 }
186
187 *pdwResult = static_cast<DWORD>(hrResult);
188
189LExit:
190 return hr;
191}
192
193static HRESULT ProcessChildMessages(
194 __in BURN_PIPE_MESSAGE* pMsg,
195 __in_opt LPVOID pvContext,
196 __out DWORD* pdwResult
197 )
198{
199 HRESULT hr = S_OK;
200 HANDLE hPipe = static_cast<HANDLE>(pvContext);
201 DWORD dwResult = 0;
202
203 // Process the message.
204 switch (pMsg->dwMessage)
205 {
206 case TEST_PARENT_SENT_MESSAGE_ID:
207 // send test message
208 hr = PipeSendMessage(hPipe, TEST_CHILD_SENT_MESSAGE_ID, (LPVOID)TEST_MESSAGE_DATA, sizeof(TEST_MESSAGE_DATA), NULL, NULL, &dwResult);
209 ExitOnFailure(hr, "Failed to send message to per-machine process.");
210 break;
211
212 default:
213 hr = E_INVALIDARG;
214 ExitOnRootFailure(hr, "Unexpected elevated message sent to child process, msg: %u", pMsg->dwMessage);
215 }
216
217 *pdwResult = dwResult;
218
219LExit:
220 return hr;
221}