aboutsummaryrefslogtreecommitdiff
path: root/src/burn/engine/approvedexe.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/burn/engine/approvedexe.cpp')
-rw-r--r--src/burn/engine/approvedexe.cpp262
1 files changed, 262 insertions, 0 deletions
diff --git a/src/burn/engine/approvedexe.cpp b/src/burn/engine/approvedexe.cpp
new file mode 100644
index 00000000..55518519
--- /dev/null
+++ b/src/burn/engine/approvedexe.cpp
@@ -0,0 +1,262 @@
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// function definitions
7
8extern "C" HRESULT ApprovedExesParseFromXml(
9 __in BURN_APPROVED_EXES* pApprovedExes,
10 __in IXMLDOMNode* pixnBundle
11 )
12{
13 HRESULT hr = S_OK;
14 IXMLDOMNodeList* pixnNodes = NULL;
15 IXMLDOMNode* pixnNode = NULL;
16 DWORD cNodes = 0;
17 LPWSTR scz = NULL;
18
19 // select approved exe nodes
20 hr = XmlSelectNodes(pixnBundle, L"ApprovedExeForElevation", &pixnNodes);
21 ExitOnFailure(hr, "Failed to select approved exe nodes.");
22
23 // get approved exe node count
24 hr = pixnNodes->get_length((long*)&cNodes);
25 ExitOnFailure(hr, "Failed to get approved exe node count.");
26
27 if (!cNodes)
28 {
29 ExitFunction();
30 }
31
32 // allocate memory for approved exes
33 pApprovedExes->rgApprovedExes = (BURN_APPROVED_EXE*)MemAlloc(sizeof(BURN_APPROVED_EXE) * cNodes, TRUE);
34 ExitOnNull(pApprovedExes->rgApprovedExes, hr, E_OUTOFMEMORY, "Failed to allocate memory for approved exe structs.");
35
36 pApprovedExes->cApprovedExes = cNodes;
37
38 // parse approved exe elements
39 for (DWORD i = 0; i < cNodes; ++i)
40 {
41 BURN_APPROVED_EXE* pApprovedExe = &pApprovedExes->rgApprovedExes[i];
42
43 hr = XmlNextElement(pixnNodes, &pixnNode, NULL);
44 ExitOnFailure(hr, "Failed to get next node.");
45
46 // @Id
47 hr = XmlGetAttributeEx(pixnNode, L"Id", &pApprovedExe->sczId);
48 ExitOnFailure(hr, "Failed to get @Id.");
49
50 // @Key
51 hr = XmlGetAttributeEx(pixnNode, L"Key", &pApprovedExe->sczKey);
52 ExitOnFailure(hr, "Failed to get @Key.");
53
54 // @ValueName
55 hr = XmlGetAttributeEx(pixnNode, L"ValueName", &pApprovedExe->sczValueName);
56 if (E_NOTFOUND != hr)
57 {
58 ExitOnFailure(hr, "Failed to get @ValueName.");
59 }
60
61 // @Win64
62 hr = XmlGetYesNoAttribute(pixnNode, L"Win64", &pApprovedExe->fWin64);
63 if (E_NOTFOUND != hr)
64 {
65 ExitOnFailure(hr, "Failed to get @Win64.");
66 }
67
68 // prepare next iteration
69 ReleaseNullObject(pixnNode);
70 ReleaseNullStr(scz);
71 }
72
73 hr = S_OK;
74
75LExit:
76 ReleaseObject(pixnNodes);
77 ReleaseObject(pixnNode);
78 ReleaseStr(scz);
79 return hr;
80}
81
82extern "C" void ApprovedExesUninitialize(
83 __in BURN_APPROVED_EXES* pApprovedExes
84 )
85{
86 if (pApprovedExes->rgApprovedExes)
87 {
88 for (DWORD i = 0; i < pApprovedExes->cApprovedExes; ++i)
89 {
90 BURN_APPROVED_EXE* pApprovedExe = &pApprovedExes->rgApprovedExes[i];
91
92 ReleaseStr(pApprovedExe->sczId);
93 ReleaseStr(pApprovedExe->sczKey);
94 ReleaseStr(pApprovedExe->sczValueName);
95 }
96 MemFree(pApprovedExes->rgApprovedExes);
97 }
98}
99
100extern "C" void ApprovedExesUninitializeLaunch(
101 __in BURN_LAUNCH_APPROVED_EXE* pLaunchApprovedExe
102 )
103{
104 if (pLaunchApprovedExe)
105 {
106 ReleaseStr(pLaunchApprovedExe->sczArguments);
107 ReleaseStr(pLaunchApprovedExe->sczExecutablePath);
108 ReleaseStr(pLaunchApprovedExe->sczId);
109 MemFree(pLaunchApprovedExe);
110 }
111}
112
113extern "C" HRESULT ApprovedExesFindById(
114 __in BURN_APPROVED_EXES* pApprovedExes,
115 __in_z LPCWSTR wzId,
116 __out BURN_APPROVED_EXE** ppApprovedExe
117 )
118{
119 HRESULT hr = S_OK;
120 BURN_APPROVED_EXE* pApprovedExe = NULL;
121
122 for (DWORD i = 0; i < pApprovedExes->cApprovedExes; ++i)
123 {
124 pApprovedExe = &pApprovedExes->rgApprovedExes[i];
125
126 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pApprovedExe->sczId, -1, wzId, -1))
127 {
128 *ppApprovedExe = pApprovedExe;
129 ExitFunction1(hr = S_OK);
130 }
131 }
132
133 hr = E_NOTFOUND;
134
135LExit:
136 return hr;
137}
138
139extern "C" HRESULT ApprovedExesLaunch(
140 __in BURN_VARIABLES* pVariables,
141 __in BURN_LAUNCH_APPROVED_EXE* pLaunchApprovedExe,
142 __out DWORD* pdwProcessId
143 )
144{
145 HRESULT hr = S_OK;
146 LPWSTR sczArgumentsFormatted = NULL;
147 LPWSTR sczArgumentsObfuscated = NULL;
148 LPWSTR sczCommand = NULL;
149 LPWSTR sczCommandObfuscated = NULL;
150 LPWSTR sczExecutableDirectory = NULL;
151 STARTUPINFOW si = { };
152 PROCESS_INFORMATION pi = { };
153
154 // build command
155 if (pLaunchApprovedExe->sczArguments && *pLaunchApprovedExe->sczArguments)
156 {
157 hr = VariableFormatString(pVariables, pLaunchApprovedExe->sczArguments, &sczArgumentsFormatted, NULL);
158 ExitOnFailure(hr, "Failed to format argument string.");
159
160 hr = StrAllocFormattedSecure(&sczCommand, L"\"%ls\" %s", pLaunchApprovedExe->sczExecutablePath, sczArgumentsFormatted);
161 ExitOnFailure(hr, "Failed to create executable command.");
162
163 hr = VariableFormatStringObfuscated(pVariables, pLaunchApprovedExe->sczArguments, &sczArgumentsObfuscated, NULL);
164 ExitOnFailure(hr, "Failed to format obfuscated argument string.");
165
166 hr = StrAllocFormatted(&sczCommandObfuscated, L"\"%ls\" %s", pLaunchApprovedExe->sczExecutablePath, sczArgumentsObfuscated);
167 }
168 else
169 {
170 hr = StrAllocFormatted(&sczCommand, L"\"%ls\"", pLaunchApprovedExe->sczExecutablePath);
171 ExitOnFailure(hr, "Failed to create executable command.");
172
173 hr = StrAllocFormatted(&sczCommandObfuscated, L"\"%ls\"", pLaunchApprovedExe->sczExecutablePath);
174 }
175 ExitOnFailure(hr, "Failed to create obfuscated executable command.");
176
177 // Try to get the directory of the executable so we can set the current directory of the process to help those executables
178 // that expect stuff to be relative to them. Best effort only.
179 hr = PathGetDirectory(pLaunchApprovedExe->sczExecutablePath, &sczExecutableDirectory);
180 if (FAILED(hr))
181 {
182 ReleaseNullStr(sczExecutableDirectory);
183 }
184
185 LogId(REPORT_STANDARD, MSG_LAUNCHING_APPROVED_EXE, pLaunchApprovedExe->sczExecutablePath, sczCommandObfuscated);
186
187 si.cb = sizeof(si);
188 if (!::CreateProcessW(pLaunchApprovedExe->sczExecutablePath, sczCommand, NULL, NULL, FALSE, CREATE_NEW_PROCESS_GROUP, NULL, sczExecutableDirectory, &si, &pi))
189 {
190 ExitWithLastError(hr, "Failed to CreateProcess on path: %ls", pLaunchApprovedExe->sczExecutablePath);
191 }
192
193 *pdwProcessId = pi.dwProcessId;
194
195 if (pLaunchApprovedExe->dwWaitForInputIdleTimeout)
196 {
197 ::WaitForInputIdle(pi.hProcess, pLaunchApprovedExe->dwWaitForInputIdleTimeout);
198 }
199
200LExit:
201 StrSecureZeroFreeString(sczArgumentsFormatted);
202 ReleaseStr(sczArgumentsObfuscated);
203 StrSecureZeroFreeString(sczCommand);
204 ReleaseStr(sczCommandObfuscated);
205 ReleaseStr(sczExecutableDirectory);
206
207 ReleaseHandle(pi.hThread);
208 ReleaseHandle(pi.hProcess);
209
210 return hr;
211}
212
213extern "C" HRESULT ApprovedExesVerifySecureLocation(
214 __in BURN_VARIABLES* pVariables,
215 __in BURN_LAUNCH_APPROVED_EXE* pLaunchApprovedExe
216 )
217{
218 HRESULT hr = S_OK;
219 LPWSTR scz = NULL;
220
221 const LPCWSTR vrgSecureFolderVariables[] = {
222 L"ProgramFiles64Folder",
223 L"ProgramFilesFolder",
224 };
225
226 for (DWORD i = 0; i < countof(vrgSecureFolderVariables); ++i)
227 {
228 LPCWSTR wzSecureFolderVariable = vrgSecureFolderVariables[i];
229
230 hr = VariableGetString(pVariables, wzSecureFolderVariable, &scz);
231 if (SUCCEEDED(hr))
232 {
233 hr = PathDirectoryContainsPath(scz, pLaunchApprovedExe->sczExecutablePath);
234 if (S_OK == hr)
235 {
236 ExitFunction();
237 }
238 }
239 else if (E_NOTFOUND != hr)
240 {
241 ExitOnFailure(hr, "Failed to get the variable: %ls", wzSecureFolderVariable);
242 }
243 }
244
245 // The problem with using a Variable for the root package cache folder is that it might not have been secured yet.
246 // Getting it through CacheGetRootCompletedPath makes sure it has been secured.
247 hr = CacheGetRootCompletedPath(TRUE, TRUE, &scz);
248 ExitOnFailure(hr, "Failed to get the root package cache folder.");
249
250 hr = PathDirectoryContainsPath(scz, pLaunchApprovedExe->sczExecutablePath);
251 if (S_OK == hr)
252 {
253 ExitFunction();
254 }
255
256 hr = S_FALSE;
257
258LExit:
259 ReleaseStr(scz);
260
261 return hr;
262}