diff options
Diffstat (limited to 'src/ext/Firewall/ca/firewall.cpp')
-rw-r--r-- | src/ext/Firewall/ca/firewall.cpp | 1085 |
1 files changed, 1085 insertions, 0 deletions
diff --git a/src/ext/Firewall/ca/firewall.cpp b/src/ext/Firewall/ca/firewall.cpp new file mode 100644 index 00000000..caae21a1 --- /dev/null +++ b/src/ext/Firewall/ca/firewall.cpp | |||
@@ -0,0 +1,1085 @@ | |||
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 | LPCWSTR vcsFirewallExceptionQuery = | ||
6 | L"SELECT `Name`, `RemoteAddresses`, `Port`, `Protocol`, `Program`, `Attributes`, `Profile`, `Component_`, `Description`, `Direction` FROM `Wix4FirewallException`"; | ||
7 | enum eFirewallExceptionQuery { feqName = 1, feqRemoteAddresses, feqPort, feqProtocol, feqProgram, feqAttributes, feqProfile, feqComponent, feqDescription }; | ||
8 | enum eFirewallExceptionTarget { fetPort = 1, fetApplication, fetUnknown }; | ||
9 | enum eFirewallExceptionAttributes { feaIgnoreFailures = 1 }; | ||
10 | |||
11 | /****************************************************************** | ||
12 | SchedFirewallExceptions - immediate custom action worker to | ||
13 | register and remove firewall exceptions. | ||
14 | |||
15 | ********************************************************************/ | ||
16 | static UINT SchedFirewallExceptions( | ||
17 | __in MSIHANDLE hInstall, | ||
18 | WCA_TODO todoSched | ||
19 | ) | ||
20 | { | ||
21 | HRESULT hr = S_OK; | ||
22 | UINT er = ERROR_SUCCESS; | ||
23 | int cFirewallExceptions = 0; | ||
24 | |||
25 | PMSIHANDLE hView = NULL; | ||
26 | PMSIHANDLE hRec = NULL; | ||
27 | |||
28 | LPWSTR pwzCustomActionData = NULL; | ||
29 | LPWSTR pwzName = NULL; | ||
30 | LPWSTR pwzRemoteAddresses = NULL; | ||
31 | LPWSTR pwzPort = NULL; | ||
32 | int iProtocol = 0; | ||
33 | int iAttributes = 0; | ||
34 | int iProfile = 0; | ||
35 | LPWSTR pwzProgram = NULL; | ||
36 | LPWSTR pwzComponent = NULL; | ||
37 | LPWSTR pwzFormattedFile = NULL; | ||
38 | LPWSTR pwzDescription = NULL; | ||
39 | int iDirection = 0; | ||
40 | |||
41 | // initialize | ||
42 | hr = WcaInitialize(hInstall, "SchedFirewallExceptions"); | ||
43 | ExitOnFailure(hr, "failed to initialize"); | ||
44 | |||
45 | // anything to do? | ||
46 | if (S_OK != WcaTableExists(L"Wix4FirewallException")) | ||
47 | { | ||
48 | WcaLog(LOGMSG_STANDARD, "Wix4FirewallException table doesn't exist, so there are no firewall exceptions to configure."); | ||
49 | ExitFunction(); | ||
50 | } | ||
51 | |||
52 | // query and loop through all the firewall exceptions | ||
53 | hr = WcaOpenExecuteView(vcsFirewallExceptionQuery, &hView); | ||
54 | ExitOnFailure(hr, "failed to open view on Wix4FirewallException table"); | ||
55 | |||
56 | while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) | ||
57 | { | ||
58 | hr = WcaGetRecordFormattedString(hRec, feqName, &pwzName); | ||
59 | ExitOnFailure(hr, "failed to get firewall exception name"); | ||
60 | |||
61 | hr = WcaGetRecordFormattedString(hRec, feqRemoteAddresses, &pwzRemoteAddresses); | ||
62 | ExitOnFailure(hr, "failed to get firewall exception remote addresses"); | ||
63 | |||
64 | hr = WcaGetRecordFormattedString(hRec, feqPort, &pwzPort); | ||
65 | ExitOnFailure(hr, "failed to get firewall exception port"); | ||
66 | |||
67 | hr = WcaGetRecordInteger(hRec, feqProtocol, &iProtocol); | ||
68 | ExitOnFailure(hr, "failed to get firewall exception protocol"); | ||
69 | |||
70 | hr = WcaGetRecordFormattedString(hRec, feqProgram, &pwzProgram); | ||
71 | ExitOnFailure(hr, "failed to get firewall exception program"); | ||
72 | |||
73 | hr = WcaGetRecordInteger(hRec, feqAttributes, &iAttributes); | ||
74 | ExitOnFailure(hr, "failed to get firewall exception attributes"); | ||
75 | |||
76 | hr = WcaGetRecordInteger(hRec, feqProfile, &iProfile); | ||
77 | ExitOnFailure(hr, "failed to get firewall exception profile"); | ||
78 | |||
79 | hr = WcaGetRecordString(hRec, feqComponent, &pwzComponent); | ||
80 | ExitOnFailure(hr, "failed to get firewall exception component"); | ||
81 | |||
82 | hr = WcaGetRecordString(hRec, feqDescription, &pwzDescription); | ||
83 | ExitOnFailure(hr, "failed to get firewall description"); | ||
84 | |||
85 | // figure out what we're doing for this exception, treating reinstall the same as install | ||
86 | WCA_TODO todoComponent = WcaGetComponentToDo(pwzComponent); | ||
87 | if ((WCA_TODO_REINSTALL == todoComponent ? WCA_TODO_INSTALL : todoComponent) != todoSched) | ||
88 | { | ||
89 | WcaLog(LOGMSG_STANDARD, "Component '%ls' action state (%d) doesn't match request (%d)", pwzComponent, todoComponent, todoSched); | ||
90 | continue; | ||
91 | } | ||
92 | |||
93 | // action :: name :: profile :: remoteaddresses :: attributes :: target :: {port::protocol | path} | ||
94 | ++cFirewallExceptions; | ||
95 | hr = WcaWriteIntegerToCaData(todoComponent, &pwzCustomActionData); | ||
96 | ExitOnFailure(hr, "failed to write exception action to custom action data"); | ||
97 | |||
98 | hr = WcaWriteStringToCaData(pwzName, &pwzCustomActionData); | ||
99 | ExitOnFailure(hr, "failed to write exception name to custom action data"); | ||
100 | |||
101 | hr = WcaWriteIntegerToCaData(iProfile, &pwzCustomActionData); | ||
102 | ExitOnFailure(hr, "failed to write exception profile to custom action data"); | ||
103 | |||
104 | hr = WcaWriteStringToCaData(pwzRemoteAddresses, &pwzCustomActionData); | ||
105 | ExitOnFailure(hr, "failed to write exception remote addresses to custom action data"); | ||
106 | |||
107 | hr = WcaWriteIntegerToCaData(iAttributes, &pwzCustomActionData); | ||
108 | ExitOnFailure(hr, "failed to write exception attributes to custom action data"); | ||
109 | |||
110 | if (*pwzProgram) | ||
111 | { | ||
112 | // If program is defined, we have an application exception. | ||
113 | hr = WcaWriteIntegerToCaData(fetApplication, &pwzCustomActionData); | ||
114 | ExitOnFailure(hr, "failed to write exception target (application) to custom action data"); | ||
115 | |||
116 | hr = WcaWriteStringToCaData(pwzProgram, &pwzCustomActionData); | ||
117 | ExitOnFailure(hr, "failed to write application path to custom action data"); | ||
118 | } | ||
119 | else | ||
120 | { | ||
121 | // we have a port-only exception | ||
122 | hr = WcaWriteIntegerToCaData(fetPort, &pwzCustomActionData); | ||
123 | ExitOnFailure(hr, "failed to write exception target (port) to custom action data"); | ||
124 | } | ||
125 | |||
126 | hr = WcaWriteStringToCaData(pwzPort, &pwzCustomActionData); | ||
127 | ExitOnFailure(hr, "failed to write application path to custom action data"); | ||
128 | |||
129 | hr = WcaWriteIntegerToCaData(iProtocol, &pwzCustomActionData); | ||
130 | ExitOnFailure(hr, "failed to write exception protocol to custom action data"); | ||
131 | |||
132 | hr = WcaWriteStringToCaData(pwzDescription, &pwzCustomActionData); | ||
133 | ExitOnFailure(hr, "failed to write firewall rule description to custom action data"); | ||
134 | |||
135 | hr = WcaWriteIntegerToCaData(iDirection, &pwzCustomActionData); | ||
136 | ExitOnFailure(hr, "failed to write firewall rule direction to custom action data"); | ||
137 | } | ||
138 | |||
139 | // reaching the end of the list is actually a good thing, not an error | ||
140 | if (E_NOMOREITEMS == hr) | ||
141 | { | ||
142 | hr = S_OK; | ||
143 | } | ||
144 | ExitOnFailure(hr, "failure occured while processing Wix4FirewallException table"); | ||
145 | |||
146 | // schedule ExecFirewallExceptions if there's anything to do | ||
147 | if (pwzCustomActionData && *pwzCustomActionData) | ||
148 | { | ||
149 | WcaLog(LOGMSG_STANDARD, "Scheduling firewall exception (%ls)", pwzCustomActionData); | ||
150 | |||
151 | if (WCA_TODO_INSTALL == todoSched) | ||
152 | { | ||
153 | hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackFirewallExceptionsInstall"), pwzCustomActionData, cFirewallExceptions * COST_FIREWALL_EXCEPTION); | ||
154 | ExitOnFailure(hr, "failed to schedule firewall install exceptions rollback"); | ||
155 | hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"ExecFirewallExceptionsInstall"), pwzCustomActionData, cFirewallExceptions * COST_FIREWALL_EXCEPTION); | ||
156 | ExitOnFailure(hr, "failed to schedule firewall install exceptions execution"); | ||
157 | } | ||
158 | else | ||
159 | { | ||
160 | hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackFirewallExceptionsUninstall"), pwzCustomActionData, cFirewallExceptions * COST_FIREWALL_EXCEPTION); | ||
161 | ExitOnFailure(hr, "failed to schedule firewall uninstall exceptions rollback"); | ||
162 | hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"ExecFirewallExceptionsUninstall"), pwzCustomActionData, cFirewallExceptions * COST_FIREWALL_EXCEPTION); | ||
163 | ExitOnFailure(hr, "failed to schedule firewall uninstall exceptions execution"); | ||
164 | } | ||
165 | } | ||
166 | else | ||
167 | { | ||
168 | WcaLog(LOGMSG_STANDARD, "No firewall exceptions scheduled"); | ||
169 | } | ||
170 | |||
171 | LExit: | ||
172 | ReleaseStr(pwzCustomActionData); | ||
173 | ReleaseStr(pwzName); | ||
174 | ReleaseStr(pwzRemoteAddresses); | ||
175 | ReleaseStr(pwzPort); | ||
176 | ReleaseStr(pwzProgram); | ||
177 | ReleaseStr(pwzComponent); | ||
178 | ReleaseStr(pwzDescription); | ||
179 | ReleaseStr(pwzFormattedFile); | ||
180 | |||
181 | return WcaFinalize(er = FAILED(hr) ? ERROR_INSTALL_FAILURE : er); | ||
182 | } | ||
183 | |||
184 | /****************************************************************** | ||
185 | SchedFirewallExceptionsInstall - immediate custom action entry | ||
186 | point to register firewall exceptions. | ||
187 | |||
188 | ********************************************************************/ | ||
189 | extern "C" UINT __stdcall SchedFirewallExceptionsInstall( | ||
190 | __in MSIHANDLE hInstall | ||
191 | ) | ||
192 | { | ||
193 | return SchedFirewallExceptions(hInstall, WCA_TODO_INSTALL); | ||
194 | } | ||
195 | |||
196 | /****************************************************************** | ||
197 | SchedFirewallExceptionsUninstall - immediate custom action entry | ||
198 | point to remove firewall exceptions. | ||
199 | |||
200 | ********************************************************************/ | ||
201 | extern "C" UINT __stdcall SchedFirewallExceptionsUninstall( | ||
202 | __in MSIHANDLE hInstall | ||
203 | ) | ||
204 | { | ||
205 | return SchedFirewallExceptions(hInstall, WCA_TODO_UNINSTALL); | ||
206 | } | ||
207 | |||
208 | /****************************************************************** | ||
209 | GetFirewallRules - Get the collection of firewall rules. | ||
210 | |||
211 | ********************************************************************/ | ||
212 | static HRESULT GetFirewallRules( | ||
213 | __in BOOL fIgnoreFailures, | ||
214 | __out INetFwRules** ppNetFwRules | ||
215 | ) | ||
216 | { | ||
217 | HRESULT hr = S_OK; | ||
218 | INetFwPolicy2* pNetFwPolicy2 = NULL; | ||
219 | INetFwRules* pNetFwRules = NULL; | ||
220 | *ppNetFwRules = NULL; | ||
221 | |||
222 | do | ||
223 | { | ||
224 | ReleaseNullObject(pNetFwPolicy2); | ||
225 | ReleaseNullObject(pNetFwRules); | ||
226 | |||
227 | if (SUCCEEDED(hr = ::CoCreateInstance(__uuidof(NetFwPolicy2), NULL, CLSCTX_ALL, __uuidof(INetFwPolicy2), (void**)&pNetFwPolicy2)) && | ||
228 | SUCCEEDED(hr = pNetFwPolicy2->get_Rules(&pNetFwRules))) | ||
229 | { | ||
230 | break; | ||
231 | } | ||
232 | else if (fIgnoreFailures) | ||
233 | { | ||
234 | ExitFunction1(hr = S_FALSE); | ||
235 | } | ||
236 | else | ||
237 | { | ||
238 | WcaLog(LOGMSG_STANDARD, "Failed to connect to Windows Firewall"); | ||
239 | UINT er = WcaErrorMessage(msierrFirewallCannotConnect, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); | ||
240 | switch (er) | ||
241 | { | ||
242 | case IDABORT: // exit with the current HRESULT | ||
243 | ExitFunction(); | ||
244 | case IDRETRY: // clean up and retry the loop | ||
245 | hr = S_FALSE; | ||
246 | break; | ||
247 | case IDIGNORE: // pass S_FALSE back to the caller, who knows how to ignore the failure | ||
248 | ExitFunction1(hr = S_FALSE); | ||
249 | default: // No UI, so default is to fail. | ||
250 | ExitFunction(); | ||
251 | } | ||
252 | } | ||
253 | } while (S_FALSE == hr); | ||
254 | |||
255 | *ppNetFwRules = pNetFwRules; | ||
256 | pNetFwRules = NULL; | ||
257 | |||
258 | LExit: | ||
259 | ReleaseObject(pNetFwPolicy2); | ||
260 | ReleaseObject(pNetFwRules); | ||
261 | |||
262 | return hr; | ||
263 | } | ||
264 | |||
265 | /****************************************************************** | ||
266 | CreateFwRuleObject - CoCreate a firewall rule, and set the common set of properties which are shared | ||
267 | between port and application firewall rules | ||
268 | |||
269 | ********************************************************************/ | ||
270 | static HRESULT CreateFwRuleObject( | ||
271 | __in BSTR bstrName, | ||
272 | __in int iProfile, | ||
273 | __in_opt LPCWSTR wzRemoteAddresses, | ||
274 | __in LPCWSTR wzPort, | ||
275 | __in int iProtocol, | ||
276 | __in LPCWSTR wzDescription, | ||
277 | __in int iDirection, | ||
278 | __out INetFwRule** ppNetFwRule | ||
279 | ) | ||
280 | { | ||
281 | HRESULT hr = S_OK; | ||
282 | BSTR bstrRemoteAddresses = NULL; | ||
283 | BSTR bstrPort = NULL; | ||
284 | BSTR bstrDescription = NULL; | ||
285 | INetFwRule* pNetFwRule = NULL; | ||
286 | *ppNetFwRule = NULL; | ||
287 | |||
288 | // convert to BSTRs to make COM happy | ||
289 | bstrRemoteAddresses = ::SysAllocString(wzRemoteAddresses); | ||
290 | ExitOnNull(bstrRemoteAddresses, hr, E_OUTOFMEMORY, "failed SysAllocString for remote addresses"); | ||
291 | bstrPort = ::SysAllocString(wzPort); | ||
292 | ExitOnNull(bstrPort, hr, E_OUTOFMEMORY, "failed SysAllocString for port"); | ||
293 | bstrDescription = ::SysAllocString(wzDescription); | ||
294 | ExitOnNull(bstrDescription, hr, E_OUTOFMEMORY, "failed SysAllocString for description"); | ||
295 | |||
296 | hr = ::CoCreateInstance(__uuidof(NetFwRule), NULL, CLSCTX_ALL, __uuidof(INetFwRule), (void**)&pNetFwRule); | ||
297 | ExitOnFailure(hr, "failed to create NetFwRule object"); | ||
298 | |||
299 | hr = pNetFwRule->put_Name(bstrName); | ||
300 | ExitOnFailure(hr, "failed to set exception name"); | ||
301 | |||
302 | hr = pNetFwRule->put_Profiles(static_cast<NET_FW_PROFILE_TYPE2>(iProfile)); | ||
303 | ExitOnFailure(hr, "failed to set exception profile"); | ||
304 | |||
305 | if (MSI_NULL_INTEGER != iProtocol) | ||
306 | { | ||
307 | hr = pNetFwRule->put_Protocol(static_cast<NET_FW_IP_PROTOCOL>(iProtocol)); | ||
308 | ExitOnFailure(hr, "failed to set exception protocol"); | ||
309 | } | ||
310 | |||
311 | if (bstrPort && *bstrPort) | ||
312 | { | ||
313 | hr = pNetFwRule->put_LocalPorts(bstrPort); | ||
314 | ExitOnFailure(hr, "failed to set exception port"); | ||
315 | } | ||
316 | |||
317 | if (bstrRemoteAddresses && *bstrRemoteAddresses) | ||
318 | { | ||
319 | hr = pNetFwRule->put_RemoteAddresses(bstrRemoteAddresses); | ||
320 | ExitOnFailure(hr, "failed to set exception remote addresses '%ls'", bstrRemoteAddresses); | ||
321 | } | ||
322 | |||
323 | if (bstrDescription && *bstrDescription) | ||
324 | { | ||
325 | hr = pNetFwRule->put_Description(bstrDescription); | ||
326 | ExitOnFailure(hr, "failed to set exception description '%ls'", bstrDescription); | ||
327 | } | ||
328 | |||
329 | if (MSI_NULL_INTEGER != iDirection) | ||
330 | { | ||
331 | hr = pNetFwRule->put_Direction(static_cast<NET_FW_RULE_DIRECTION> (iDirection)); | ||
332 | ExitOnFailure(hr, "failed to set exception direction"); | ||
333 | } | ||
334 | |||
335 | *ppNetFwRule = pNetFwRule; | ||
336 | pNetFwRule = NULL; | ||
337 | |||
338 | LExit: | ||
339 | ReleaseBSTR(bstrRemoteAddresses); | ||
340 | ReleaseBSTR(bstrPort); | ||
341 | ReleaseBSTR(bstrDescription); | ||
342 | ReleaseObject(pNetFwRule); | ||
343 | |||
344 | return hr; | ||
345 | } | ||
346 | |||
347 | /****************************************************************** | ||
348 | FSupportProfiles - Returns true if we support profiles on this machine. | ||
349 | (Only on Vista or later) | ||
350 | |||
351 | ********************************************************************/ | ||
352 | static BOOL FSupportProfiles() | ||
353 | { | ||
354 | BOOL fSupportProfiles = FALSE; | ||
355 | INetFwRules* pNetFwRules = NULL; | ||
356 | |||
357 | // We only support profiles if we can co-create an instance of NetFwPolicy2. | ||
358 | // This will not work on pre-vista machines. | ||
359 | if (SUCCEEDED(GetFirewallRules(TRUE, &pNetFwRules)) && pNetFwRules != NULL) | ||
360 | { | ||
361 | fSupportProfiles = TRUE; | ||
362 | ReleaseObject(pNetFwRules); | ||
363 | } | ||
364 | |||
365 | return fSupportProfiles; | ||
366 | } | ||
367 | |||
368 | /****************************************************************** | ||
369 | GetCurrentFirewallProfile - get the active firewall profile as an | ||
370 | INetFwProfile, which owns the lists of exceptions we're | ||
371 | updating. | ||
372 | |||
373 | ********************************************************************/ | ||
374 | static HRESULT GetCurrentFirewallProfile( | ||
375 | __in BOOL fIgnoreFailures, | ||
376 | __out INetFwProfile** ppfwProfile | ||
377 | ) | ||
378 | { | ||
379 | HRESULT hr = S_OK; | ||
380 | INetFwMgr* pfwMgr = NULL; | ||
381 | INetFwPolicy* pfwPolicy = NULL; | ||
382 | INetFwProfile* pfwProfile = NULL; | ||
383 | *ppfwProfile = NULL; | ||
384 | |||
385 | do | ||
386 | { | ||
387 | ReleaseNullObject(pfwPolicy); | ||
388 | ReleaseNullObject(pfwMgr); | ||
389 | ReleaseNullObject(pfwProfile); | ||
390 | |||
391 | if (SUCCEEDED(hr = ::CoCreateInstance(__uuidof(NetFwMgr), NULL, CLSCTX_INPROC_SERVER, __uuidof(INetFwMgr), (void**)&pfwMgr)) && | ||
392 | SUCCEEDED(hr = pfwMgr->get_LocalPolicy(&pfwPolicy)) && | ||
393 | SUCCEEDED(hr = pfwPolicy->get_CurrentProfile(&pfwProfile))) | ||
394 | { | ||
395 | break; | ||
396 | } | ||
397 | else if (fIgnoreFailures) | ||
398 | { | ||
399 | ExitFunction1(hr = S_FALSE); | ||
400 | } | ||
401 | else | ||
402 | { | ||
403 | WcaLog(LOGMSG_STANDARD, "Failed to connect to Windows Firewall"); | ||
404 | UINT er = WcaErrorMessage(msierrFirewallCannotConnect, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); | ||
405 | switch (er) | ||
406 | { | ||
407 | case IDABORT: // exit with the current HRESULT | ||
408 | ExitFunction(); | ||
409 | case IDRETRY: // clean up and retry the loop | ||
410 | hr = S_FALSE; | ||
411 | break; | ||
412 | case IDIGNORE: // pass S_FALSE back to the caller, who knows how to ignore the failure | ||
413 | ExitFunction1(hr = S_FALSE); | ||
414 | default: // No UI, so default is to fail. | ||
415 | ExitFunction(); | ||
416 | } | ||
417 | } | ||
418 | } while (S_FALSE == hr); | ||
419 | |||
420 | *ppfwProfile = pfwProfile; | ||
421 | pfwProfile = NULL; | ||
422 | |||
423 | LExit: | ||
424 | ReleaseObject(pfwPolicy); | ||
425 | ReleaseObject(pfwMgr); | ||
426 | ReleaseObject(pfwProfile); | ||
427 | |||
428 | return hr; | ||
429 | } | ||
430 | |||
431 | /****************************************************************** | ||
432 | AddApplicationException | ||
433 | |||
434 | ********************************************************************/ | ||
435 | static HRESULT AddApplicationException( | ||
436 | __in LPCWSTR wzFile, | ||
437 | __in LPCWSTR wzName, | ||
438 | __in int iProfile, | ||
439 | __in_opt LPCWSTR wzRemoteAddresses, | ||
440 | __in BOOL fIgnoreFailures, | ||
441 | __in LPCWSTR wzPort, | ||
442 | __in int iProtocol, | ||
443 | __in LPCWSTR wzDescription, | ||
444 | __in int iDirection | ||
445 | ) | ||
446 | { | ||
447 | HRESULT hr = S_OK; | ||
448 | BSTR bstrFile = NULL; | ||
449 | BSTR bstrName = NULL; | ||
450 | INetFwRules* pNetFwRules = NULL; | ||
451 | INetFwRule* pNetFwRule = NULL; | ||
452 | |||
453 | // convert to BSTRs to make COM happy | ||
454 | bstrFile = ::SysAllocString(wzFile); | ||
455 | ExitOnNull(bstrFile, hr, E_OUTOFMEMORY, "failed SysAllocString for path"); | ||
456 | bstrName = ::SysAllocString(wzName); | ||
457 | ExitOnNull(bstrName, hr, E_OUTOFMEMORY, "failed SysAllocString for name"); | ||
458 | |||
459 | // get the collection of firewall rules | ||
460 | hr = GetFirewallRules(fIgnoreFailures, &pNetFwRules); | ||
461 | ExitOnFailure(hr, "failed to get firewall rules object"); | ||
462 | if (S_FALSE == hr) // user or package author chose to ignore missing firewall | ||
463 | { | ||
464 | ExitFunction(); | ||
465 | } | ||
466 | |||
467 | // try to find it (i.e., support reinstall) | ||
468 | hr = pNetFwRules->Item(bstrName, &pNetFwRule); | ||
469 | if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) | ||
470 | { | ||
471 | hr = CreateFwRuleObject(bstrName, iProfile, wzRemoteAddresses, wzPort, iProtocol, wzDescription, iDirection, &pNetFwRule); | ||
472 | ExitOnFailure(hr, "failed to create FwRule object"); | ||
473 | |||
474 | // set edge traversal to true | ||
475 | hr = pNetFwRule->put_EdgeTraversal(VARIANT_TRUE); | ||
476 | ExitOnFailure(hr, "failed to set application exception edgetraversal property"); | ||
477 | |||
478 | // set path | ||
479 | hr = pNetFwRule->put_ApplicationName(bstrFile); | ||
480 | ExitOnFailure(hr, "failed to set application name"); | ||
481 | |||
482 | // enable it | ||
483 | hr = pNetFwRule->put_Enabled(VARIANT_TRUE); | ||
484 | ExitOnFailure(hr, "failed to to enable application exception"); | ||
485 | |||
486 | // add it to the list of authorized apps | ||
487 | hr = pNetFwRules->Add(pNetFwRule); | ||
488 | ExitOnFailure(hr, "failed to add app to the authorized apps list"); | ||
489 | } | ||
490 | else | ||
491 | { | ||
492 | // we found an existing app exception (if we succeeded, that is) | ||
493 | ExitOnFailure(hr, "failed trying to find existing app"); | ||
494 | |||
495 | // enable it (just in case it was disabled) | ||
496 | pNetFwRule->put_Enabled(VARIANT_TRUE); | ||
497 | } | ||
498 | |||
499 | LExit: | ||
500 | ReleaseBSTR(bstrName); | ||
501 | ReleaseBSTR(bstrFile); | ||
502 | ReleaseObject(pNetFwRules); | ||
503 | ReleaseObject(pNetFwRule); | ||
504 | |||
505 | return fIgnoreFailures ? S_OK : hr; | ||
506 | } | ||
507 | |||
508 | /****************************************************************** | ||
509 | AddApplicationExceptionOnCurrentProfile | ||
510 | |||
511 | ********************************************************************/ | ||
512 | static HRESULT AddApplicationExceptionOnCurrentProfile( | ||
513 | __in LPCWSTR wzFile, | ||
514 | __in LPCWSTR wzName, | ||
515 | __in_opt LPCWSTR wzRemoteAddresses, | ||
516 | __in BOOL fIgnoreFailures | ||
517 | ) | ||
518 | { | ||
519 | HRESULT hr = S_OK; | ||
520 | BSTR bstrFile = NULL; | ||
521 | BSTR bstrName = NULL; | ||
522 | BSTR bstrRemoteAddresses = NULL; | ||
523 | INetFwProfile* pfwProfile = NULL; | ||
524 | INetFwAuthorizedApplications* pfwApps = NULL; | ||
525 | INetFwAuthorizedApplication* pfwApp = NULL; | ||
526 | |||
527 | // convert to BSTRs to make COM happy | ||
528 | bstrFile = ::SysAllocString(wzFile); | ||
529 | ExitOnNull(bstrFile, hr, E_OUTOFMEMORY, "failed SysAllocString for path"); | ||
530 | bstrName = ::SysAllocString(wzName); | ||
531 | ExitOnNull(bstrName, hr, E_OUTOFMEMORY, "failed SysAllocString for name"); | ||
532 | bstrRemoteAddresses = ::SysAllocString(wzRemoteAddresses); | ||
533 | ExitOnNull(bstrRemoteAddresses, hr, E_OUTOFMEMORY, "failed SysAllocString for remote addresses"); | ||
534 | |||
535 | // get the firewall profile, which is our entry point for adding exceptions | ||
536 | hr = GetCurrentFirewallProfile(fIgnoreFailures, &pfwProfile); | ||
537 | ExitOnFailure(hr, "failed to get firewall profile"); | ||
538 | if (S_FALSE == hr) // user or package author chose to ignore missing firewall | ||
539 | { | ||
540 | ExitFunction(); | ||
541 | } | ||
542 | |||
543 | // first, let's see if the app is already on the exception list | ||
544 | hr = pfwProfile->get_AuthorizedApplications(&pfwApps); | ||
545 | ExitOnFailure(hr, "failed to get list of authorized apps"); | ||
546 | |||
547 | // try to find it (i.e., support reinstall) | ||
548 | hr = pfwApps->Item(bstrFile, &pfwApp); | ||
549 | if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) | ||
550 | { | ||
551 | // not found, so we get to add it | ||
552 | hr = ::CoCreateInstance(__uuidof(NetFwAuthorizedApplication), NULL, CLSCTX_INPROC_SERVER, __uuidof(INetFwAuthorizedApplication), reinterpret_cast<void**>(&pfwApp)); | ||
553 | ExitOnFailure(hr, "failed to create authorized app"); | ||
554 | |||
555 | // set the display name | ||
556 | hr = pfwApp->put_Name(bstrName); | ||
557 | ExitOnFailure(hr, "failed to set authorized app name"); | ||
558 | |||
559 | // set path | ||
560 | hr = pfwApp->put_ProcessImageFileName(bstrFile); | ||
561 | ExitOnFailure(hr, "failed to set authorized app path"); | ||
562 | |||
563 | // set the allowed remote addresses | ||
564 | if (bstrRemoteAddresses && *bstrRemoteAddresses) | ||
565 | { | ||
566 | hr = pfwApp->put_RemoteAddresses(bstrRemoteAddresses); | ||
567 | ExitOnFailure(hr, "failed to set authorized app remote addresses"); | ||
568 | } | ||
569 | |||
570 | // add it to the list of authorized apps | ||
571 | hr = pfwApps->Add(pfwApp); | ||
572 | ExitOnFailure(hr, "failed to add app to the authorized apps list"); | ||
573 | } | ||
574 | else | ||
575 | { | ||
576 | // we found an existing app exception (if we succeeded, that is) | ||
577 | ExitOnFailure(hr, "failed trying to find existing app"); | ||
578 | |||
579 | // enable it (just in case it was disabled) | ||
580 | pfwApp->put_Enabled(VARIANT_TRUE); | ||
581 | } | ||
582 | |||
583 | LExit: | ||
584 | ReleaseBSTR(bstrRemoteAddresses); | ||
585 | ReleaseBSTR(bstrName); | ||
586 | ReleaseBSTR(bstrFile); | ||
587 | ReleaseObject(pfwApp); | ||
588 | ReleaseObject(pfwApps); | ||
589 | ReleaseObject(pfwProfile); | ||
590 | |||
591 | return fIgnoreFailures ? S_OK : hr; | ||
592 | } | ||
593 | |||
594 | /****************************************************************** | ||
595 | AddPortException | ||
596 | |||
597 | ********************************************************************/ | ||
598 | static HRESULT AddPortException( | ||
599 | __in LPCWSTR wzName, | ||
600 | __in int iProfile, | ||
601 | __in_opt LPCWSTR wzRemoteAddresses, | ||
602 | __in BOOL fIgnoreFailures, | ||
603 | __in LPCWSTR wzPort, | ||
604 | __in int iProtocol, | ||
605 | __in LPCWSTR wzDescription, | ||
606 | __in int iDirection | ||
607 | ) | ||
608 | { | ||
609 | HRESULT hr = S_OK; | ||
610 | BSTR bstrName = NULL; | ||
611 | INetFwRules* pNetFwRules = NULL; | ||
612 | INetFwRule* pNetFwRule = NULL; | ||
613 | |||
614 | // convert to BSTRs to make COM happy | ||
615 | bstrName = ::SysAllocString(wzName); | ||
616 | ExitOnNull(bstrName, hr, E_OUTOFMEMORY, "failed SysAllocString for name"); | ||
617 | |||
618 | // get the collection of firewall rules | ||
619 | hr = GetFirewallRules(fIgnoreFailures, &pNetFwRules); | ||
620 | ExitOnFailure(hr, "failed to get firewall rules object"); | ||
621 | if (S_FALSE == hr) // user or package author chose to ignore missing firewall | ||
622 | { | ||
623 | ExitFunction(); | ||
624 | } | ||
625 | |||
626 | // try to find it (i.e., support reinstall) | ||
627 | hr = pNetFwRules->Item(bstrName, &pNetFwRule); | ||
628 | if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) | ||
629 | { | ||
630 | hr = CreateFwRuleObject(bstrName, iProfile, wzRemoteAddresses, wzPort, iProtocol, wzDescription, iDirection, &pNetFwRule); | ||
631 | ExitOnFailure(hr, "failed to create FwRule object"); | ||
632 | |||
633 | // enable it | ||
634 | hr = pNetFwRule->put_Enabled(VARIANT_TRUE); | ||
635 | ExitOnFailure(hr, "failed to to enable port exception"); | ||
636 | |||
637 | // add it to the list of authorized ports | ||
638 | hr = pNetFwRules->Add(pNetFwRule); | ||
639 | ExitOnFailure(hr, "failed to add app to the authorized ports list"); | ||
640 | } | ||
641 | else | ||
642 | { | ||
643 | // we found an existing port exception (if we succeeded, that is) | ||
644 | ExitOnFailure(hr, "failed trying to find existing port rule"); | ||
645 | |||
646 | // enable it (just in case it was disabled) | ||
647 | pNetFwRule->put_Enabled(VARIANT_TRUE); | ||
648 | } | ||
649 | |||
650 | LExit: | ||
651 | ReleaseBSTR(bstrName); | ||
652 | ReleaseObject(pNetFwRules); | ||
653 | ReleaseObject(pNetFwRule); | ||
654 | |||
655 | return fIgnoreFailures ? S_OK : hr; | ||
656 | } | ||
657 | |||
658 | /****************************************************************** | ||
659 | AddPortExceptionOnCurrentProfile | ||
660 | |||
661 | ********************************************************************/ | ||
662 | static HRESULT AddPortExceptionOnCurrentProfile( | ||
663 | __in LPCWSTR wzName, | ||
664 | __in_opt LPCWSTR wzRemoteAddresses, | ||
665 | __in BOOL fIgnoreFailures, | ||
666 | __in int iPort, | ||
667 | __in int iProtocol | ||
668 | ) | ||
669 | { | ||
670 | HRESULT hr = S_OK; | ||
671 | BSTR bstrName = NULL; | ||
672 | BSTR bstrRemoteAddresses = NULL; | ||
673 | INetFwProfile* pfwProfile = NULL; | ||
674 | INetFwOpenPorts* pfwPorts = NULL; | ||
675 | INetFwOpenPort* pfwPort = NULL; | ||
676 | |||
677 | // convert to BSTRs to make COM happy | ||
678 | bstrName = ::SysAllocString(wzName); | ||
679 | ExitOnNull(bstrName, hr, E_OUTOFMEMORY, "failed SysAllocString for name"); | ||
680 | bstrRemoteAddresses = ::SysAllocString(wzRemoteAddresses); | ||
681 | ExitOnNull(bstrRemoteAddresses, hr, E_OUTOFMEMORY, "failed SysAllocString for remote addresses"); | ||
682 | |||
683 | // create and initialize a new open port object | ||
684 | hr = ::CoCreateInstance(__uuidof(NetFwOpenPort), NULL, CLSCTX_INPROC_SERVER, __uuidof(INetFwOpenPort), reinterpret_cast<void**>(&pfwPort)); | ||
685 | ExitOnFailure(hr, "failed to create new open port"); | ||
686 | |||
687 | hr = pfwPort->put_Port(iPort); | ||
688 | ExitOnFailure(hr, "failed to set exception port"); | ||
689 | |||
690 | hr = pfwPort->put_Protocol(static_cast<NET_FW_IP_PROTOCOL>(iProtocol)); | ||
691 | ExitOnFailure(hr, "failed to set exception protocol"); | ||
692 | |||
693 | if (bstrRemoteAddresses && *bstrRemoteAddresses) | ||
694 | { | ||
695 | hr = pfwPort->put_RemoteAddresses(bstrRemoteAddresses); | ||
696 | ExitOnFailure(hr, "failed to set exception remote addresses '%ls'", bstrRemoteAddresses); | ||
697 | } | ||
698 | |||
699 | hr = pfwPort->put_Name(bstrName); | ||
700 | ExitOnFailure(hr, "failed to set exception name"); | ||
701 | |||
702 | // get the firewall profile, its current list of open ports, and add ours | ||
703 | hr = GetCurrentFirewallProfile(fIgnoreFailures, &pfwProfile); | ||
704 | ExitOnFailure(hr, "failed to get firewall profile"); | ||
705 | if (S_FALSE == hr) // user or package author chose to ignore missing firewall | ||
706 | { | ||
707 | ExitFunction(); | ||
708 | } | ||
709 | |||
710 | hr = pfwProfile->get_GloballyOpenPorts(&pfwPorts); | ||
711 | ExitOnFailure(hr, "failed to get open ports"); | ||
712 | |||
713 | hr = pfwPorts->Add(pfwPort); | ||
714 | ExitOnFailure(hr, "failed to add exception to global list"); | ||
715 | |||
716 | LExit: | ||
717 | ReleaseBSTR(bstrRemoteAddresses); | ||
718 | ReleaseBSTR(bstrName); | ||
719 | ReleaseObject(pfwProfile); | ||
720 | ReleaseObject(pfwPorts); | ||
721 | ReleaseObject(pfwPort); | ||
722 | |||
723 | return fIgnoreFailures ? S_OK : hr; | ||
724 | } | ||
725 | |||
726 | /****************************************************************** | ||
727 | RemoveException - Removes the exception rule with the given name. | ||
728 | |||
729 | ********************************************************************/ | ||
730 | static HRESULT RemoveException( | ||
731 | __in LPCWSTR wzName, | ||
732 | __in BOOL fIgnoreFailures | ||
733 | ) | ||
734 | { | ||
735 | HRESULT hr = S_OK;; | ||
736 | INetFwRules* pNetFwRules = NULL; | ||
737 | |||
738 | // convert to BSTRs to make COM happy | ||
739 | BSTR bstrName = ::SysAllocString(wzName); | ||
740 | ExitOnNull(bstrName, hr, E_OUTOFMEMORY, "failed SysAllocString for path"); | ||
741 | |||
742 | // get the collection of firewall rules | ||
743 | hr = GetFirewallRules(fIgnoreFailures, &pNetFwRules); | ||
744 | ExitOnFailure(hr, "failed to get firewall rules object"); | ||
745 | if (S_FALSE == hr) // user or package author chose to ignore missing firewall | ||
746 | { | ||
747 | ExitFunction(); | ||
748 | } | ||
749 | |||
750 | hr = pNetFwRules->Remove(bstrName); | ||
751 | ExitOnFailure(hr, "failed to remove authorized app"); | ||
752 | |||
753 | LExit: | ||
754 | ReleaseBSTR(bstrName); | ||
755 | ReleaseObject(pNetFwRules); | ||
756 | |||
757 | return fIgnoreFailures ? S_OK : hr; | ||
758 | } | ||
759 | |||
760 | /****************************************************************** | ||
761 | RemoveApplicationExceptionFromCurrentProfile | ||
762 | |||
763 | ********************************************************************/ | ||
764 | static HRESULT RemoveApplicationExceptionFromCurrentProfile( | ||
765 | __in LPCWSTR wzFile, | ||
766 | __in BOOL fIgnoreFailures | ||
767 | ) | ||
768 | { | ||
769 | HRESULT hr = S_OK; | ||
770 | INetFwProfile* pfwProfile = NULL; | ||
771 | INetFwAuthorizedApplications* pfwApps = NULL; | ||
772 | |||
773 | // convert to BSTRs to make COM happy | ||
774 | BSTR bstrFile = ::SysAllocString(wzFile); | ||
775 | ExitOnNull(bstrFile, hr, E_OUTOFMEMORY, "failed SysAllocString for path"); | ||
776 | |||
777 | // get the firewall profile, which is our entry point for removing exceptions | ||
778 | hr = GetCurrentFirewallProfile(fIgnoreFailures, &pfwProfile); | ||
779 | ExitOnFailure(hr, "failed to get firewall profile"); | ||
780 | if (S_FALSE == hr) // user or package author chose to ignore missing firewall | ||
781 | { | ||
782 | ExitFunction(); | ||
783 | } | ||
784 | |||
785 | // now get the list of app exceptions and remove the one | ||
786 | hr = pfwProfile->get_AuthorizedApplications(&pfwApps); | ||
787 | ExitOnFailure(hr, "failed to get list of authorized apps"); | ||
788 | |||
789 | hr = pfwApps->Remove(bstrFile); | ||
790 | ExitOnFailure(hr, "failed to remove authorized app"); | ||
791 | |||
792 | LExit: | ||
793 | ReleaseBSTR(bstrFile); | ||
794 | ReleaseObject(pfwApps); | ||
795 | ReleaseObject(pfwProfile); | ||
796 | |||
797 | return fIgnoreFailures ? S_OK : hr; | ||
798 | } | ||
799 | |||
800 | /****************************************************************** | ||
801 | RemovePortExceptionFromCurrentProfile | ||
802 | |||
803 | ********************************************************************/ | ||
804 | static HRESULT RemovePortExceptionFromCurrentProfile( | ||
805 | __in int iPort, | ||
806 | __in int iProtocol, | ||
807 | __in BOOL fIgnoreFailures | ||
808 | ) | ||
809 | { | ||
810 | HRESULT hr = S_OK; | ||
811 | INetFwProfile* pfwProfile = NULL; | ||
812 | INetFwOpenPorts* pfwPorts = NULL; | ||
813 | |||
814 | // get the firewall profile, which is our entry point for adding exceptions | ||
815 | hr = GetCurrentFirewallProfile(fIgnoreFailures, &pfwProfile); | ||
816 | ExitOnFailure(hr, "failed to get firewall profile"); | ||
817 | if (S_FALSE == hr) // user or package author chose to ignore missing firewall | ||
818 | { | ||
819 | ExitFunction(); | ||
820 | } | ||
821 | |||
822 | hr = pfwProfile->get_GloballyOpenPorts(&pfwPorts); | ||
823 | ExitOnFailure(hr, "failed to get open ports"); | ||
824 | |||
825 | hr = pfwPorts->Remove(iPort, static_cast<NET_FW_IP_PROTOCOL>(iProtocol)); | ||
826 | ExitOnFailure(hr, "failed to remove open port %d, protocol %d", iPort, iProtocol); | ||
827 | |||
828 | LExit: | ||
829 | return fIgnoreFailures ? S_OK : hr; | ||
830 | } | ||
831 | |||
832 | static HRESULT AddApplicationException( | ||
833 | __in BOOL fSupportProfiles, | ||
834 | __in LPCWSTR wzFile, | ||
835 | __in LPCWSTR wzName, | ||
836 | __in int iProfile, | ||
837 | __in_opt LPCWSTR wzRemoteAddresses, | ||
838 | __in BOOL fIgnoreFailures, | ||
839 | __in LPCWSTR wzPort, | ||
840 | __in int iProtocol, | ||
841 | __in LPCWSTR wzDescription, | ||
842 | __in int iDirection | ||
843 | ) | ||
844 | { | ||
845 | HRESULT hr = S_OK; | ||
846 | |||
847 | if (fSupportProfiles) | ||
848 | { | ||
849 | hr = AddApplicationException(wzFile, wzName, iProfile, wzRemoteAddresses, fIgnoreFailures, wzPort, iProtocol, wzDescription, iDirection); | ||
850 | } | ||
851 | else | ||
852 | { | ||
853 | if (0 != *wzPort || MSI_NULL_INTEGER != iProtocol) | ||
854 | { | ||
855 | // NOTE: This is treated as an error rather than either creating a rule based on just the application (no port), or | ||
856 | // just the port because it is unclear what is the proper fall back. For example, suppose that you have code that | ||
857 | // runs in dllhost.exe. Clearly falling back to opening all of dllhost is wrong. Because the firewall is a security | ||
858 | // feature, it seems better to require the MSI author to indicate the behavior that they want. | ||
859 | WcaLog(LOGMSG_STANDARD, "FirewallExtension: Cannot add firewall rule '%ls', which defines both an application and a port or protocol. Such a rule requires Microsoft Windows Vista or later.", wzName); | ||
860 | return fIgnoreFailures ? S_OK : E_NOTIMPL; | ||
861 | } | ||
862 | |||
863 | hr = AddApplicationExceptionOnCurrentProfile(wzFile, wzName, wzRemoteAddresses, fIgnoreFailures); | ||
864 | } | ||
865 | |||
866 | return hr; | ||
867 | } | ||
868 | |||
869 | static HRESULT AddPortException( | ||
870 | __in BOOL fSupportProfiles, | ||
871 | __in LPCWSTR wzName, | ||
872 | __in int iProfile, | ||
873 | __in_opt LPCWSTR wzRemoteAddresses, | ||
874 | __in BOOL fIgnoreFailures, | ||
875 | __in LPCWSTR wzPort, | ||
876 | __in int iProtocol, | ||
877 | __in LPCWSTR wzDescription, | ||
878 | __in int iDirection | ||
879 | ) | ||
880 | { | ||
881 | HRESULT hr = S_OK; | ||
882 | |||
883 | if (fSupportProfiles) | ||
884 | { | ||
885 | hr = AddPortException(wzName, iProfile, wzRemoteAddresses, fIgnoreFailures, wzPort, iProtocol, wzDescription, iDirection); | ||
886 | } | ||
887 | else | ||
888 | { | ||
889 | hr = AddPortExceptionOnCurrentProfile(wzName, wzRemoteAddresses, fIgnoreFailures, wcstol(wzPort, NULL, 10), iProtocol); | ||
890 | } | ||
891 | |||
892 | return hr; | ||
893 | } | ||
894 | |||
895 | static HRESULT RemoveApplicationException( | ||
896 | __in BOOL fSupportProfiles, | ||
897 | __in LPCWSTR wzName, | ||
898 | __in LPCWSTR wzFile, | ||
899 | __in BOOL fIgnoreFailures, | ||
900 | __in LPCWSTR wzPort, | ||
901 | __in int iProtocol | ||
902 | ) | ||
903 | { | ||
904 | HRESULT hr = S_OK; | ||
905 | |||
906 | if (fSupportProfiles) | ||
907 | { | ||
908 | hr = RemoveException(wzName, fIgnoreFailures); | ||
909 | } | ||
910 | else | ||
911 | { | ||
912 | if (0 != *wzPort || MSI_NULL_INTEGER != iProtocol) | ||
913 | { | ||
914 | WcaLog(LOGMSG_STANDARD, "FirewallExtension: Cannot remove firewall rule '%ls', which defines both an application and a port or protocol. Such a rule requires Microsoft Windows Vista or later.", wzName); | ||
915 | return S_OK; | ||
916 | } | ||
917 | |||
918 | hr = RemoveApplicationExceptionFromCurrentProfile(wzFile, fIgnoreFailures); | ||
919 | } | ||
920 | |||
921 | return hr; | ||
922 | } | ||
923 | |||
924 | static HRESULT RemovePortException( | ||
925 | __in BOOL fSupportProfiles, | ||
926 | __in LPCWSTR wzName, | ||
927 | __in LPCWSTR wzPort, | ||
928 | __in int iProtocol, | ||
929 | __in BOOL fIgnoreFailures | ||
930 | ) | ||
931 | { | ||
932 | HRESULT hr = S_OK; | ||
933 | |||
934 | if (fSupportProfiles) | ||
935 | { | ||
936 | hr = RemoveException(wzName, fIgnoreFailures); | ||
937 | } | ||
938 | else | ||
939 | { | ||
940 | hr = RemovePortExceptionFromCurrentProfile(wcstol(wzPort, NULL, 10), iProtocol, fIgnoreFailures); | ||
941 | } | ||
942 | |||
943 | return hr; | ||
944 | } | ||
945 | |||
946 | /****************************************************************** | ||
947 | ExecFirewallExceptions - deferred custom action entry point to | ||
948 | register and remove firewall exceptions. | ||
949 | |||
950 | ********************************************************************/ | ||
951 | extern "C" UINT __stdcall ExecFirewallExceptions( | ||
952 | __in MSIHANDLE hInstall | ||
953 | ) | ||
954 | { | ||
955 | HRESULT hr = S_OK; | ||
956 | BOOL fSupportProfiles = FALSE; | ||
957 | LPWSTR pwz = NULL; | ||
958 | LPWSTR pwzCustomActionData = NULL; | ||
959 | int iTodo = WCA_TODO_UNKNOWN; | ||
960 | LPWSTR pwzName = NULL; | ||
961 | LPWSTR pwzRemoteAddresses = NULL; | ||
962 | int iAttributes = 0; | ||
963 | int iTarget = fetUnknown; | ||
964 | LPWSTR pwzFile = NULL; | ||
965 | LPWSTR pwzPort = NULL; | ||
966 | LPWSTR pwzDescription = NULL; | ||
967 | int iProtocol = 0; | ||
968 | int iProfile = 0; | ||
969 | int iDirection = 0; | ||
970 | |||
971 | // initialize | ||
972 | hr = WcaInitialize(hInstall, "ExecFirewallExceptions"); | ||
973 | ExitOnFailure(hr, "failed to initialize"); | ||
974 | |||
975 | hr = WcaGetProperty( L"CustomActionData", &pwzCustomActionData); | ||
976 | ExitOnFailure(hr, "failed to get CustomActionData"); | ||
977 | WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData); | ||
978 | |||
979 | hr = ::CoInitialize(NULL); | ||
980 | ExitOnFailure(hr, "failed to initialize COM"); | ||
981 | |||
982 | // Find out if we support profiles (only on Vista or later) | ||
983 | fSupportProfiles = FSupportProfiles(); | ||
984 | |||
985 | // loop through all the passed in data | ||
986 | pwz = pwzCustomActionData; | ||
987 | while (pwz && *pwz) | ||
988 | { | ||
989 | // extract the custom action data and if rolling back, swap INSTALL and UNINSTALL | ||
990 | hr = WcaReadIntegerFromCaData(&pwz, &iTodo); | ||
991 | ExitOnFailure(hr, "failed to read todo from custom action data"); | ||
992 | if (::MsiGetMode(hInstall, MSIRUNMODE_ROLLBACK)) | ||
993 | { | ||
994 | if (WCA_TODO_INSTALL == iTodo) | ||
995 | { | ||
996 | iTodo = WCA_TODO_UNINSTALL; | ||
997 | } | ||
998 | else if (WCA_TODO_UNINSTALL == iTodo) | ||
999 | { | ||
1000 | iTodo = WCA_TODO_INSTALL; | ||
1001 | } | ||
1002 | } | ||
1003 | |||
1004 | hr = WcaReadStringFromCaData(&pwz, &pwzName); | ||
1005 | ExitOnFailure(hr, "failed to read name from custom action data"); | ||
1006 | |||
1007 | hr = WcaReadIntegerFromCaData(&pwz, &iProfile); | ||
1008 | ExitOnFailure(hr, "failed to read profile from custom action data"); | ||
1009 | |||
1010 | hr = WcaReadStringFromCaData(&pwz, &pwzRemoteAddresses); | ||
1011 | ExitOnFailure(hr, "failed to read remote addresses from custom action data"); | ||
1012 | |||
1013 | hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); | ||
1014 | ExitOnFailure(hr, "failed to read attributes from custom action data"); | ||
1015 | BOOL fIgnoreFailures = feaIgnoreFailures == (iAttributes & feaIgnoreFailures); | ||
1016 | |||
1017 | hr = WcaReadIntegerFromCaData(&pwz, &iTarget); | ||
1018 | ExitOnFailure(hr, "failed to read target from custom action data"); | ||
1019 | |||
1020 | if (iTarget == fetApplication) | ||
1021 | { | ||
1022 | hr = WcaReadStringFromCaData(&pwz, &pwzFile); | ||
1023 | ExitOnFailure(hr, "failed to read file path from custom action data"); | ||
1024 | } | ||
1025 | |||
1026 | hr = WcaReadStringFromCaData(&pwz, &pwzPort); | ||
1027 | ExitOnFailure(hr, "failed to read port from custom action data"); | ||
1028 | hr = WcaReadIntegerFromCaData(&pwz, &iProtocol); | ||
1029 | ExitOnFailure(hr, "failed to read protocol from custom action data"); | ||
1030 | hr = WcaReadStringFromCaData(&pwz, &pwzDescription); | ||
1031 | ExitOnFailure(hr, "failed to read protocol from custom action data"); | ||
1032 | hr = WcaReadIntegerFromCaData(&pwz, &iDirection); | ||
1033 | ExitOnFailure(hr, "failed to read direction from custom action data"); | ||
1034 | |||
1035 | switch (iTarget) | ||
1036 | { | ||
1037 | case fetPort: | ||
1038 | switch (iTodo) | ||
1039 | { | ||
1040 | case WCA_TODO_INSTALL: | ||
1041 | case WCA_TODO_REINSTALL: | ||
1042 | WcaLog(LOGMSG_STANDARD, "Installing firewall exception2 %ls on port %ls, protocol %d", pwzName, pwzPort, iProtocol); | ||
1043 | hr = AddPortException(fSupportProfiles, pwzName, iProfile, pwzRemoteAddresses, fIgnoreFailures, pwzPort, iProtocol, pwzDescription, iDirection); | ||
1044 | ExitOnFailure(hr, "failed to add/update port exception for name '%ls' on port %ls, protocol %d", pwzName, pwzPort, iProtocol); | ||
1045 | break; | ||
1046 | |||
1047 | case WCA_TODO_UNINSTALL: | ||
1048 | WcaLog(LOGMSG_STANDARD, "Uninstalling firewall exception2 %ls on port %ls, protocol %d", pwzName, pwzPort, iProtocol); | ||
1049 | hr = RemovePortException(fSupportProfiles, pwzName, pwzPort, iProtocol, fIgnoreFailures); | ||
1050 | ExitOnFailure(hr, "failed to remove port exception for name '%ls' on port %ls, protocol %d", pwzName, pwzPort, iProtocol); | ||
1051 | break; | ||
1052 | } | ||
1053 | break; | ||
1054 | |||
1055 | case fetApplication: | ||
1056 | switch (iTodo) | ||
1057 | { | ||
1058 | case WCA_TODO_INSTALL: | ||
1059 | case WCA_TODO_REINSTALL: | ||
1060 | WcaLog(LOGMSG_STANDARD, "Installing firewall exception2 %ls (%ls)", pwzName, pwzFile); | ||
1061 | hr = AddApplicationException(fSupportProfiles, pwzFile, pwzName, iProfile, pwzRemoteAddresses, fIgnoreFailures, pwzPort, iProtocol, pwzDescription, iDirection); | ||
1062 | ExitOnFailure(hr, "failed to add/update application exception for name '%ls', file '%ls'", pwzName, pwzFile); | ||
1063 | break; | ||
1064 | |||
1065 | case WCA_TODO_UNINSTALL: | ||
1066 | WcaLog(LOGMSG_STANDARD, "Uninstalling firewall exception2 %ls (%ls)", pwzName, pwzFile); | ||
1067 | hr = RemoveApplicationException(fSupportProfiles, pwzName, pwzFile, fIgnoreFailures, pwzPort, iProtocol); | ||
1068 | ExitOnFailure(hr, "failed to remove application exception for name '%ls', file '%ls'", pwzName, pwzFile); | ||
1069 | break; | ||
1070 | } | ||
1071 | break; | ||
1072 | } | ||
1073 | } | ||
1074 | |||
1075 | LExit: | ||
1076 | ReleaseStr(pwzCustomActionData); | ||
1077 | ReleaseStr(pwzName); | ||
1078 | ReleaseStr(pwzRemoteAddresses); | ||
1079 | ReleaseStr(pwzFile); | ||
1080 | ReleaseStr(pwzPort); | ||
1081 | ReleaseStr(pwzDescription); | ||
1082 | ::CoUninitialize(); | ||
1083 | |||
1084 | return WcaFinalize(FAILED(hr) ? ERROR_INSTALL_FAILURE : ERROR_SUCCESS); | ||
1085 | } | ||