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