diff options
Diffstat (limited to 'src/test/BurnUnitTest/ElevationTest.cpp')
-rw-r--r-- | src/test/BurnUnitTest/ElevationTest.cpp | 218 |
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 | |||
6 | const DWORD TEST_CHILD_SENT_MESSAGE_ID = 0xFFFE; | ||
7 | const DWORD TEST_PARENT_SENT_MESSAGE_ID = 0xFFFF; | ||
8 | const HRESULT S_TEST_SUCCEEDED = 0x3133; | ||
9 | const char TEST_MESSAGE_DATA[] = "{94949868-7EAE-4ac5-BEAC-AFCA2821DE01}"; | ||
10 | |||
11 | |||
12 | static BOOL STDAPICALLTYPE ElevateTest_ShellExecuteExW( | ||
13 | __inout LPSHELLEXECUTEINFOW lpExecInfo | ||
14 | ); | ||
15 | static DWORD CALLBACK ElevateTest_ThreadProc( | ||
16 | __in LPVOID lpThreadParameter | ||
17 | ); | ||
18 | static HRESULT ProcessParentMessages( | ||
19 | __in BURN_PIPE_MESSAGE* pMsg, | ||
20 | __in_opt LPVOID pvContext, | ||
21 | __out DWORD* pdwResult | ||
22 | ); | ||
23 | static HRESULT ProcessChildMessages( | ||
24 | __in BURN_PIPE_MESSAGE* pMsg, | ||
25 | __in_opt LPVOID pvContext, | ||
26 | __out DWORD* pdwResult | ||
27 | ); | ||
28 | |||
29 | namespace Microsoft | ||
30 | { | ||
31 | namespace Tools | ||
32 | { | ||
33 | namespace WindowsInstallerXml | ||
34 | { | ||
35 | namespace Test | ||
36 | { | ||
37 | namespace 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 | |||
103 | static 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 | |||
118 | LExit: | ||
119 | ReleaseStr(scz); | ||
120 | |||
121 | return SUCCEEDED(hr); | ||
122 | } | ||
123 | |||
124 | static 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 | |||
153 | LExit: | ||
154 | PipeConnectionUninitialize(&connection); | ||
155 | ReleaseStr(sczArguments); | ||
156 | |||
157 | return FAILED(hr) ? (DWORD)hr : result.dwResult; | ||
158 | } | ||
159 | |||
160 | static 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 | |||
186 | LExit: | ||
187 | return hr; | ||
188 | } | ||
189 | |||
190 | static 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 | |||
216 | LExit: | ||
217 | return hr; | ||
218 | } | ||