@joebigelow / wix-1 / commits / dfb7512b

add firewall extension decompiler, make msi modifications work, add all attributes

chris_bednarski committed Sep 21, 2023 at 16:03 UTC dfb7512b85536b7726080648f2228cf8d0153724
35 files changed +3356 -347
src/ext/Firewall/ca/firewall.cpp
+783 -197
@@ -3,34 +3,54 @@
3 #include "precomp.h"
4
5 LPCWSTR vcsFirewallExceptionQuery =
6 - L"SELECT `Name`, `RemoteAddresses`, `Port`, `Protocol`, `Program`, `Attributes`, `Profile`, `Component_`, `Description`, `Direction` FROM `Wix5FirewallException`";
7 -enum eFirewallExceptionQuery { feqName = 1, feqRemoteAddresses, feqPort, feqProtocol, feqProgram, feqAttributes, feqProfile, feqComponent, feqDescription, feqDirection };
8 -enum eFirewallExceptionTarget { fetPort = 1, fetApplication, fetUnknown };
9 -enum eFirewallExceptionAttributes { feaIgnoreFailures = 1 };
6 +L"SELECT `Name`, `RemoteAddresses`, `Port`, `Protocol`, `Program`, `Attributes`, `Profile`, `Component_`, `Description`, `Direction`, `Action`, `EdgeTraversal`, `Enabled`, `Grouping`, `IcmpTypesAndCodes`, `Interfaces`, `InterfaceTypes`, `LocalAddresses`, `RemotePort`, `ServiceName`, `LocalAppPackageId`, `LocalUserAuthorizedList`, `LocalUserOwner`, `RemoteMachineAuthorizedList`, `RemoteUserAuthorizedList`, `SecureFlags` FROM `Wix5FirewallException`";
7 +enum eFirewallExceptionQuery { feqName = 1, feqRemoteAddresses, feqPort, feqProtocol, feqProgram, feqAttributes, feqProfile, feqComponent, feqDescription, feqDirection, feqAction, feqEdgeTraversal, feqEnabled, feqGrouping, feqIcmpTypesAndCodes, feqInterfaces, feqInterfaceTypes, feqLocalAddresses, feqRemotePort, feqServiceName, feqLocalAppPackageId, feqLocalUserAuthorizedList, feqLocalUserOwner, feqRemoteMachineAuthorizedList, feqRemoteUserAuthorizedList, feqSecureFlags };
8 +enum eFirewallExceptionAttributes { feaIgnoreFailures = 1, feaIgnoreUpdates = 2, feaEnableOnUpdate = 4, feaAddINetFwRule2 = 8, feaAddINetFwRule3 = 16 };
9
10 struct FIREWALL_EXCEPTION_ATTRIBUTES
11 {
12 LPWSTR pwzName;
14 -
15 - LPWSTR pwzRemoteAddresses;
16 - LPWSTR pwzPort;
17 - int iProtocol;
18 - LPWSTR pwzProgram;
13 int iAttributes;
20 - int iProfile;
14 +
15 + // INetFwRule
16 + int iAction;
17 + LPWSTR pwzApplicationName;
18 LPWSTR pwzDescription;
19 int iDirection;
20 + int iEnabled;
21 + LPWSTR pwzGrouping;
22 + LPWSTR pwzIcmpTypesAndCodes;
23 + LPWSTR pwzInterfaces;
24 + LPWSTR pwzInterfaceTypes;
25 + LPWSTR pwzLocalAddresses;
26 + LPWSTR pwzLocalPorts;
27 + int iProfile;
28 + int iProtocol;
29 + LPWSTR pwzRemoteAddresses;
30 + LPWSTR pwzRemotePorts;
31 + LPWSTR pwzServiceName;
32 +
33 + // INetFwRule2
34 + int iEdgeTraversal;
35 +
36 + // INetFwRule3
37 + LPWSTR pwzLocalAppPackageId;
38 + LPWSTR pwzLocalUserAuthorizedList;
39 + LPWSTR pwzLocalUserOwner;
40 + LPWSTR pwzRemoteMachineAuthorizedList;
41 + LPWSTR pwzRemoteUserAuthorizedList;
42 + int iSecureFlags;
43 };
44
45 /******************************************************************
26 - SchedFirewallExceptions - immediate custom action worker to
46 + SchedFirewallExceptions - immediate custom action worker to
47 register and remove firewall exceptions.
48
49 ********************************************************************/
50 static UINT SchedFirewallExceptions(
51 __in MSIHANDLE hInstall,
32 - WCA_TODO todoSched
33 - )
52 + __in WCA_TODO todoSched
53 +)
54 {
55 HRESULT hr = S_OK;
56 UINT er = ERROR_SUCCESS;
@@ -67,19 +87,19 @@ static UINT SchedFirewallExceptions(
87 hr = WcaGetRecordFormattedString(hRec, feqRemoteAddresses, &attrs.pwzRemoteAddresses);
88 ExitOnFailure(hr, "Failed to get firewall exception remote addresses.");
89
70 - hr = WcaGetRecordFormattedString(hRec, feqPort, &attrs.pwzPort);
90 + hr = WcaGetRecordFormattedString(hRec, feqPort, &attrs.pwzLocalPorts);
91 ExitOnFailure(hr, "Failed to get firewall exception port.");
92
73 - hr = WcaGetRecordInteger(hRec, feqProtocol, &attrs.iProtocol);
93 + hr = WcaGetRecordFormattedInteger(hRec, feqProtocol, &attrs.iProtocol);
94 ExitOnFailure(hr, "Failed to get firewall exception protocol.");
95
76 - hr = WcaGetRecordFormattedString(hRec, feqProgram, &attrs.pwzProgram);
96 + hr = WcaGetRecordFormattedString(hRec, feqProgram, &attrs.pwzApplicationName);
97 ExitOnFailure(hr, "Failed to get firewall exception program.");
98
99 hr = WcaGetRecordInteger(hRec, feqAttributes, &attrs.iAttributes);
100 ExitOnFailure(hr, "Failed to get firewall exception attributes.");
81 -
82 - hr = WcaGetRecordInteger(hRec, feqProfile, &attrs.iProfile);
101 +
102 + hr = WcaGetRecordFormattedInteger(hRec, feqProfile, &attrs.iProfile);
103 ExitOnFailure(hr, "Failed to get firewall exception profile.");
104
105 hr = WcaGetRecordString(hRec, feqComponent, &pwzComponent);
@@ -91,6 +111,54 @@ static UINT SchedFirewallExceptions(
111 hr = WcaGetRecordInteger(hRec, feqDirection, &attrs.iDirection);
112 ExitOnFailure(hr, "Failed to get firewall exception direction.");
113
114 + hr = WcaGetRecordFormattedInteger(hRec, feqAction, &attrs.iAction);
115 + ExitOnFailure(hr, "Failed to get firewall exception action.");
116 +
117 + hr = WcaGetRecordFormattedInteger(hRec, feqEdgeTraversal, &attrs.iEdgeTraversal);
118 + ExitOnFailure(hr, "Failed to get firewall exception edge traversal.");
119 +
120 + hr = WcaGetRecordFormattedInteger(hRec, feqEnabled, &attrs.iEnabled);
121 + ExitOnFailure(hr, "Failed to get firewall exception enabled flag.");
122 +
123 + hr = WcaGetRecordFormattedString(hRec, feqGrouping, &attrs.pwzGrouping);
124 + ExitOnFailure(hr, "Failed to get firewall exception grouping.");
125 +
126 + hr = WcaGetRecordFormattedString(hRec, feqIcmpTypesAndCodes, &attrs.pwzIcmpTypesAndCodes);
127 + ExitOnFailure(hr, "Failed to get firewall exception ICMP types and codes.");
128 +
129 + hr = WcaGetRecordFormattedString(hRec, feqInterfaces, &attrs.pwzInterfaces);
130 + ExitOnFailure(hr, "Failed to get firewall exception interfaces.");
131 +
132 + hr = WcaGetRecordFormattedString(hRec, feqInterfaceTypes, &attrs.pwzInterfaceTypes);
133 + ExitOnFailure(hr, "Failed to get firewall exception interface types.");
134 +
135 + hr = WcaGetRecordFormattedString(hRec, feqLocalAddresses, &attrs.pwzLocalAddresses);
136 + ExitOnFailure(hr, "Failed to get firewall exception local addresses.");
137 +
138 + hr = WcaGetRecordFormattedString(hRec, feqRemotePort, &attrs.pwzRemotePorts);
139 + ExitOnFailure(hr, "Failed to get firewall exception remote port.");
140 +
141 + hr = WcaGetRecordFormattedString(hRec, feqServiceName, &attrs.pwzServiceName);
142 + ExitOnFailure(hr, "Failed to get firewall exception service name.");
143 +
144 + hr = WcaGetRecordFormattedString(hRec, feqLocalAppPackageId, &attrs.pwzLocalAppPackageId);
145 + ExitOnFailure(hr, "Failed to get firewall exception local app package id.");
146 +
147 + hr = WcaGetRecordFormattedString(hRec, feqLocalUserAuthorizedList, &attrs.pwzLocalUserAuthorizedList);
148 + ExitOnFailure(hr, "Failed to get firewall exception local user authorized list.");
149 +
150 + hr = WcaGetRecordFormattedString(hRec, feqLocalUserOwner, &attrs.pwzLocalUserOwner);
151 + ExitOnFailure(hr, "Failed to get firewall exception local user owner.");
152 +
153 + hr = WcaGetRecordFormattedString(hRec, feqRemoteMachineAuthorizedList, &attrs.pwzRemoteMachineAuthorizedList);
154 + ExitOnFailure(hr, "Failed to get firewall exception remote machine authorized list.");
155 +
156 + hr = WcaGetRecordFormattedString(hRec, feqRemoteUserAuthorizedList, &attrs.pwzRemoteUserAuthorizedList);
157 + ExitOnFailure(hr, "Failed to get firewall exception remote user authorized list.");
158 +
159 + hr = WcaGetRecordFormattedInteger(hRec, feqSecureFlags, &attrs.iSecureFlags);
160 + ExitOnFailure(hr, "Failed to get firewall exception secure flag.");
161 +
162 // figure out what we're doing for this exception, treating reinstall the same as install
163 WCA_TODO todoComponent = WcaGetComponentToDo(pwzComponent);
164 if ((WCA_TODO_REINSTALL == todoComponent ? WCA_TODO_INSTALL : todoComponent) != todoSched)
@@ -99,7 +167,6 @@ static UINT SchedFirewallExceptions(
167 continue;
168 }
169
102 - // action :: name :: profile :: remoteaddresses :: attributes :: target :: {port::protocol | path}
170 ++cFirewallExceptions;
171 hr = WcaWriteIntegerToCaData(todoComponent, &pwzCustomActionData);
172 ExitOnFailure(hr, "failed to write exception action to custom action data");
@@ -116,40 +183,75 @@ static UINT SchedFirewallExceptions(
183 hr = WcaWriteIntegerToCaData(attrs.iAttributes, &pwzCustomActionData);
184 ExitOnFailure(hr, "failed to write exception attributes to custom action data");
185
119 - if (*attrs.pwzProgram)
120 - {
121 - // If program is defined, we have an application exception.
122 - hr = WcaWriteIntegerToCaData(fetApplication, &pwzCustomActionData);
123 - ExitOnFailure(hr, "failed to write exception target (application) to custom action data");
124 -
125 - hr = WcaWriteStringToCaData(attrs.pwzProgram, &pwzCustomActionData);
126 - ExitOnFailure(hr, "failed to write application path to custom action data");
127 - }
128 - else
129 - {
130 - // we have a port-only exception
131 - hr = WcaWriteIntegerToCaData(fetPort, &pwzCustomActionData);
132 - ExitOnFailure(hr, "failed to write exception target (port) to custom action data");
133 - }
134 -
135 - hr = WcaWriteStringToCaData(attrs.pwzPort, &pwzCustomActionData);
186 + hr = WcaWriteStringToCaData(attrs.pwzApplicationName, &pwzCustomActionData);
187 ExitOnFailure(hr, "failed to write application path to custom action data");
188
189 + hr = WcaWriteStringToCaData(attrs.pwzLocalPorts, &pwzCustomActionData);
190 + ExitOnFailure(hr, "failed to write local ports to custom action data");
191 +
192 hr = WcaWriteIntegerToCaData(attrs.iProtocol, &pwzCustomActionData);
193 ExitOnFailure(hr, "failed to write exception protocol to custom action data");
194
195 hr = WcaWriteStringToCaData(attrs.pwzDescription, &pwzCustomActionData);
142 - ExitOnFailure(hr, "failed to write firewall rule description to custom action data");
196 + ExitOnFailure(hr, "failed to write firewall exception description to custom action data");
197
198 hr = WcaWriteIntegerToCaData(attrs.iDirection, &pwzCustomActionData);
145 - ExitOnFailure(hr, "failed to write firewall rule direction to custom action data");
199 + ExitOnFailure(hr, "failed to write firewall exception direction to custom action data");
200 +
201 + hr = WcaWriteIntegerToCaData(attrs.iAction, &pwzCustomActionData);
202 + ExitOnFailure(hr, "failed to write exception action to custom action data");
203 +
204 + hr = WcaWriteIntegerToCaData(attrs.iEdgeTraversal, &pwzCustomActionData);
205 + ExitOnFailure(hr, "failed to write exception edge traversal to custom action data");
206 +
207 + hr = WcaWriteIntegerToCaData(attrs.iEnabled, &pwzCustomActionData);
208 + ExitOnFailure(hr, "failed to write exception enabled flag to custom action data");
209 +
210 + hr = WcaWriteStringToCaData(attrs.pwzGrouping, &pwzCustomActionData);
211 + ExitOnFailure(hr, "failed to write grouping to custom action data");
212 +
213 + hr = WcaWriteStringToCaData(attrs.pwzIcmpTypesAndCodes, &pwzCustomActionData);
214 + ExitOnFailure(hr, "failed to write icmp types and codes to custom action data");
215 +
216 + hr = WcaWriteStringToCaData(attrs.pwzInterfaces, &pwzCustomActionData);
217 + ExitOnFailure(hr, "failed to write interfaces to custom action data");
218 +
219 + hr = WcaWriteStringToCaData(attrs.pwzInterfaceTypes, &pwzCustomActionData);
220 + ExitOnFailure(hr, "failed to write interface types to custom action data");
221 +
222 + hr = WcaWriteStringToCaData(attrs.pwzLocalAddresses, &pwzCustomActionData);
223 + ExitOnFailure(hr, "failed to write local addresses to custom action data");
224 +
225 + hr = WcaWriteStringToCaData(attrs.pwzRemotePorts, &pwzCustomActionData);
226 + ExitOnFailure(hr, "failed to write remote ports to custom action data");
227 +
228 + hr = WcaWriteStringToCaData(attrs.pwzServiceName, &pwzCustomActionData);
229 + ExitOnFailure(hr, "failed to write service name to custom action data");
230 +
231 + hr = WcaWriteStringToCaData(attrs.pwzLocalAppPackageId, &pwzCustomActionData);
232 + ExitOnFailure(hr, "failed to write local app package id to custom action data");
233 +
234 + hr = WcaWriteStringToCaData(attrs.pwzLocalUserAuthorizedList, &pwzCustomActionData);
235 + ExitOnFailure(hr, "failed to write local user authorized list to custom action data");
236 +
237 + hr = WcaWriteStringToCaData(attrs.pwzLocalUserOwner, &pwzCustomActionData);
238 + ExitOnFailure(hr, "failed to write local user owner to custom action data");
239 +
240 + hr = WcaWriteStringToCaData(attrs.pwzRemoteMachineAuthorizedList, &pwzCustomActionData);
241 + ExitOnFailure(hr, "failed to write remote machine authorized list to custom action data");
242 +
243 + hr = WcaWriteStringToCaData(attrs.pwzRemoteUserAuthorizedList, &pwzCustomActionData);
244 + ExitOnFailure(hr, "failed to write remote user authorized list to custom action data");
245 +
246 + hr = WcaWriteIntegerToCaData(attrs.iSecureFlags, &pwzCustomActionData);
247 + ExitOnFailure(hr, "failed to write exception secure flags to custom action data");
248 }
249
250 // reaching the end of the list is actually a good thing, not an error
251 if (E_NOMOREITEMS == hr)
252 {
253 hr = S_OK;
152 - }
254 + }
255 ExitOnFailure(hr, "failure occured while processing Wix5FirewallException table");
256
257 // schedule ExecFirewallExceptions if there's anything to do
@@ -160,14 +262,14 @@ static UINT SchedFirewallExceptions(
262 if (WCA_TODO_INSTALL == todoSched)
263 {
264 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION5(L"RollbackFirewallExceptionsInstall"), pwzCustomActionData, cFirewallExceptions * COST_FIREWALL_EXCEPTION);
163 - ExitOnFailure(hr, "failed to schedule firewall install exceptions rollback");
265 + ExitOnFailure(hr, "failed to schedule firewall install exceptions rollback");
266 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION5(L"ExecFirewallExceptionsInstall"), pwzCustomActionData, cFirewallExceptions * COST_FIREWALL_EXCEPTION);
267 ExitOnFailure(hr, "failed to schedule firewall install exceptions execution");
268 }
269 else
270 {
271 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION5(L"RollbackFirewallExceptionsUninstall"), pwzCustomActionData, cFirewallExceptions * COST_FIREWALL_EXCEPTION);
170 - ExitOnFailure(hr, "failed to schedule firewall uninstall exceptions rollback");
272 + ExitOnFailure(hr, "failed to schedule firewall uninstall exceptions rollback");
273 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION5(L"ExecFirewallExceptionsUninstall"), pwzCustomActionData, cFirewallExceptions * COST_FIREWALL_EXCEPTION);
274 ExitOnFailure(hr, "failed to schedule firewall uninstall exceptions execution");
275 }
@@ -180,53 +282,68 @@ static UINT SchedFirewallExceptions(
282 LExit:
283 ReleaseStr(attrs.pwzName);
284 ReleaseStr(attrs.pwzRemoteAddresses);
183 - ReleaseStr(attrs.pwzPort);
184 - ReleaseStr(attrs.pwzProgram);
285 + ReleaseStr(attrs.pwzLocalPorts);
286 + ReleaseStr(attrs.pwzApplicationName);
287 ReleaseStr(attrs.pwzDescription);
288 + ReleaseStr(attrs.pwzGrouping);
289 + ReleaseStr(attrs.pwzIcmpTypesAndCodes);
290 + ReleaseStr(attrs.pwzInterfaces);
291 + ReleaseStr(attrs.pwzInterfaceTypes);
292 + ReleaseStr(attrs.pwzLocalAddresses);
293 + ReleaseStr(attrs.pwzRemotePorts);
294 + ReleaseStr(attrs.pwzServiceName);
295 + ReleaseStr(attrs.pwzLocalAppPackageId);
296 + ReleaseStr(attrs.pwzLocalUserAuthorizedList);
297 + ReleaseStr(attrs.pwzLocalUserOwner);
298 + ReleaseStr(attrs.pwzRemoteMachineAuthorizedList);
299 + ReleaseStr(attrs.pwzRemoteUserAuthorizedList);
300 ReleaseStr(pwzComponent);
301 ReleaseStr(pwzCustomActionData);
302
303 return WcaFinalize(er = FAILED(hr) ? ERROR_INSTALL_FAILURE : er);
304 }
305
192 -/******************************************************************
306 +
307 +/*******************************************************************
308 SchedFirewallExceptionsInstall - immediate custom action entry
309 point to register firewall exceptions.
310
311 ********************************************************************/
312 extern "C" UINT __stdcall SchedFirewallExceptionsInstall(
313 __in MSIHANDLE hInstall
199 - )
314 +)
315 {
316 return SchedFirewallExceptions(hInstall, WCA_TODO_INSTALL);
317 }
318
204 -/******************************************************************
319 +
320 +/*******************************************************************
321 SchedFirewallExceptionsUninstall - immediate custom action entry
322 point to remove firewall exceptions.
323
324 ********************************************************************/
325 extern "C" UINT __stdcall SchedFirewallExceptionsUninstall(
326 __in MSIHANDLE hInstall
211 - )
327 +)
328 {
329 return SchedFirewallExceptions(hInstall, WCA_TODO_UNINSTALL);
330 }
331
216 -/******************************************************************
332 +
333 +/*******************************************************************
334 GetFirewallRules - Get the collection of firewall rules.
335
336 ********************************************************************/
337 static HRESULT GetFirewallRules(
338 __in BOOL fIgnoreFailures,
339 __out INetFwRules** ppNetFwRules
223 - )
340 +)
341 {
342 HRESULT hr = S_OK;
343 INetFwPolicy2* pNetFwPolicy2 = NULL;
344 INetFwRules* pNetFwRules = NULL;
345 *ppNetFwRules = NULL;
229 -
346 +
347 do
348 {
349 ReleaseNullObject(pNetFwPolicy2);
@@ -262,7 +379,7 @@ static HRESULT GetFirewallRules(
379
380 *ppNetFwRules = pNetFwRules;
381 pNetFwRules = NULL;
265 -
382 +
383 LExit:
384 ReleaseObject(pNetFwPolicy2);
385 ReleaseObject(pNetFwRules);
@@ -270,51 +387,380 @@ LExit:
387 return hr;
388 }
389
273 -/******************************************************************
274 - CreateFwRuleObject - CoCreate a firewall rule, and set the common set of properties which are shared
275 - between port and application firewall rules
390 +
391 +/*******************************************************************
392 + CreateFwRuleObject - CoCreate a firewall rule, and set the name
393
394 ********************************************************************/
395 static HRESULT CreateFwRuleObject(
396 __in BSTR bstrName,
280 - __in FIREWALL_EXCEPTION_ATTRIBUTES const& attrs,
397 __out INetFwRule** ppNetFwRule
282 - )
398 +)
399 +{
400 + HRESULT hr = S_OK;
401 + INetFwRule* pNetFwRule = NULL;
402 + *ppNetFwRule = NULL;
403 +
404 + hr = ::CoCreateInstance(__uuidof(NetFwRule), NULL, CLSCTX_ALL, __uuidof(INetFwRule), (LPVOID*)&pNetFwRule);
405 + ExitOnFailure(hr, "failed to create NetFwRule object");
406 +
407 + hr = pNetFwRule->put_Name(bstrName);
408 + ExitOnFailure(hr, "failed to set firewall exception name");
409 +
410 + *ppNetFwRule = pNetFwRule;
411 +
412 +LExit:
413 + return hr;
414 +}
415 +
416 +
417 +/*********************************************************************
418 + GetFwRuleInterfaces - pack firewall rule interfaces into a VARIANT.
419 + The populated VARIANT needs to be cleaned up by the calling function.
420 +
421 +**********************************************************************/
422 +static HRESULT GetFwRuleInterfaces(
423 + __in FIREWALL_EXCEPTION_ATTRIBUTES const& attrs,
424 + __out VARIANT& vInterfaces
425 +)
426 +{
427 + HRESULT hr = S_OK;
428 + BSTR bstrInterfaces = NULL;
429 + const WCHAR FORBIDDEN_FIREWALL_CHAR = L'|';
430 + LONG iInterfacesCount = 0;
431 + UINT iLength = 0;
432 + LONG iIndex = 0;
433 +
434 + ::VariantInit(&vInterfaces);
435 + ExitOnNull(attrs.pwzInterfaces, hr, S_OK, "No interfaces to pack");
436 +
437 + bstrInterfaces = ::SysAllocString(attrs.pwzInterfaces);
438 + ExitOnNull(bstrInterfaces, hr, E_OUTOFMEMORY, "failed SysAllocString for interfaces");
439 +
440 + iLength = ::SysStringLen(bstrInterfaces);
441 +
442 + LPWSTR pwzT = bstrInterfaces;
443 + while (*pwzT)
444 + {
445 + if (FORBIDDEN_FIREWALL_CHAR == *pwzT)
446 + {
447 + *pwzT = L'\0';
448 + pwzT++;
449 +
450 + // skip empty values inside the interfaces eg. |||
451 + if (*pwzT && FORBIDDEN_FIREWALL_CHAR != *pwzT)
452 + {
453 + iInterfacesCount++;
454 + }
455 + }
456 + else
457 + {
458 + if (pwzT == bstrInterfaces)
459 + {
460 + iInterfacesCount++;
461 + }
462 +
463 + pwzT++;
464 + }
465 + }
466 +
467 + ExitOnNull(iInterfacesCount, hr, S_OK, "All interfaces are empty values");
468 +
469 + vInterfaces.vt = VT_ARRAY | VT_VARIANT;
470 + // this will be cleaned up by ReleaseVariant call of the calling function
471 + vInterfaces.parray = SafeArrayCreateVector(VT_VARIANT, 0, iInterfacesCount);
472 +
473 + for (LPCWSTR pwzElement = bstrInterfaces; pwzElement < (bstrInterfaces + iLength); ++pwzElement)
474 + {
475 + if (*pwzElement)
476 + {
477 + VARIANT vElement;
478 + ::VariantInit(&vElement);
479 +
480 + vElement.vt = VT_BSTR;
481 + // this will be cleaned up by ReleaseVariant call of the calling function
482 + vElement.bstrVal = ::SysAllocString(pwzElement);
483 + ExitOnNull(vElement.bstrVal, hr, E_OUTOFMEMORY, "failed SysAllocString for interface element");
484 +
485 + hr = SafeArrayPutElement(vInterfaces.parray, &iIndex, &vElement);
486 + ExitOnFailure(hr, "failed to put interface '%ls' into safe array", pwzElement);
487 +
488 + pwzElement += ::SysStringLen(vElement.bstrVal);
489 + iIndex++;
490 + }
491 + }
492 +
493 +LExit:
494 + ReleaseBSTR(bstrInterfaces);
495 +
496 + return hr;
497 +}
498 +
499 +/******************************************************************************
500 + UpdateFwRule2Object - update properties for a firewall INetFwRule2 interface.
501 + Requires Windows 7 / 2008 R2
502 +
503 + ******************************************************************************/
504 +static HRESULT UpdateFwRule2Object(
505 + __in INetFwRule* pNetFwRule,
506 + __in BOOL fUpdateRule,
507 + __in FIREWALL_EXCEPTION_ATTRIBUTES const& attrs
508 +)
509 {
510 HRESULT hr = S_OK;
511 + INetFwRule2* pNetFwRule2 = NULL;
512 +
513 + hr = pNetFwRule->QueryInterface(__uuidof(INetFwRule2), (LPVOID*)&pNetFwRule2);
514 + ExitOnFailure(hr, "failed to query INetFwRule2 interface");
515 +
516 + if (MSI_NULL_INTEGER != attrs.iEdgeTraversal)
517 + {
518 + hr = pNetFwRule2->put_EdgeTraversalOptions(attrs.iEdgeTraversal);
519 + ExitOnFailure(hr, "failed to set exception edge traversal option");
520 + }
521 + else if (fUpdateRule)
522 + {
523 + hr = pNetFwRule2->put_EdgeTraversalOptions(NET_FW_EDGE_TRAVERSAL_TYPE_DENY);
524 + ExitOnFailure(hr, "failed to remove exception edge traversal option");
525 + }
526 +
527 +LExit:
528 + ReleaseObject(pNetFwRule2);
529 +
530 + return hr;
531 +}
532 +
533 +
534 +/******************************************************************************
535 + UpdateFwRule3Object - update properties for a firewall INetFwRule3 interface.
536 + Requires Windows 8 / 2012
537 +
538 + ******************************************************************************/
539 +static HRESULT UpdateFwRule3Object(
540 + __in INetFwRule* pNetFwRule,
541 + __in BOOL fUpdateRule,
542 + __in FIREWALL_EXCEPTION_ATTRIBUTES const& attrs
543 +)
544 +{
545 + HRESULT hr = S_OK;
546 +
547 + BSTR bstrLocalAppPackageId = NULL;
548 + BSTR bstrLocalUserAuthorizedList = NULL;
549 + BSTR bstrLocalUserOwner = NULL;
550 + BSTR bstrRemoteMachineAuthorizedList = NULL;
551 + BSTR bstrRemoteUserAuthorizedList = NULL;
552 + INetFwRule3* pNetFwRule3 = NULL;
553 +
554 + bstrLocalAppPackageId = ::SysAllocString(attrs.pwzLocalAppPackageId);
555 + ExitOnNull(bstrLocalAppPackageId, hr, E_OUTOFMEMORY, "failed SysAllocString for local app package id");
556 + bstrLocalUserAuthorizedList = ::SysAllocString(attrs.pwzLocalUserAuthorizedList);
557 + ExitOnNull(bstrLocalUserAuthorizedList, hr, E_OUTOFMEMORY, "failed SysAllocString for local user authorized list");
558 + bstrLocalUserOwner = ::SysAllocString(attrs.pwzLocalUserOwner);
559 + ExitOnNull(bstrLocalUserOwner, hr, E_OUTOFMEMORY, "failed SysAllocString for local user owner");
560 + bstrRemoteMachineAuthorizedList = ::SysAllocString(attrs.pwzRemoteMachineAuthorizedList);
561 + ExitOnNull(bstrRemoteMachineAuthorizedList, hr, E_OUTOFMEMORY, "failed SysAllocString for remote machine authorized list");
562 + bstrRemoteUserAuthorizedList = ::SysAllocString(attrs.pwzRemoteUserAuthorizedList);
563 + ExitOnNull(bstrRemoteUserAuthorizedList, hr, E_OUTOFMEMORY, "failed SysAllocString for remote user authorized list");
564 +
565 + hr = pNetFwRule->QueryInterface(__uuidof(INetFwRule3), (LPVOID*)&pNetFwRule3);
566 + ExitOnFailure(hr, "failed to query INetFwRule3 interface");
567 +
568 + if (bstrLocalAppPackageId && *bstrLocalAppPackageId)
569 + {
570 + hr = pNetFwRule3->put_LocalAppPackageId(bstrLocalAppPackageId);
571 + ExitOnFailure(hr, "failed to set exception local app package id");
572 + }
573 + else if (fUpdateRule)
574 + {
575 + hr = pNetFwRule3->put_LocalAppPackageId(NULL);
576 + ExitOnFailure(hr, "failed to remove exception local app package id");
577 + }
578 +
579 + if (bstrLocalUserAuthorizedList && *bstrLocalUserAuthorizedList)
580 + {
581 + hr = pNetFwRule3->put_LocalUserAuthorizedList(bstrLocalUserAuthorizedList);
582 + ExitOnFailure(hr, "failed to set exception local user authorized list");
583 + }
584 + else if (fUpdateRule)
585 + {
586 + hr = pNetFwRule3->put_LocalUserAuthorizedList(NULL);
587 + ExitOnFailure(hr, "failed to remove exception local user authorized list");
588 + }
589 +
590 + if (bstrLocalUserOwner && *bstrLocalUserOwner)
591 + {
592 + hr = pNetFwRule3->put_LocalUserOwner(bstrLocalUserOwner);
593 + ExitOnFailure(hr, "failed to set exception local user owner");
594 + }
595 + else if (fUpdateRule)
596 + {
597 + hr = pNetFwRule3->put_LocalUserOwner(NULL);
598 + ExitOnFailure(hr, "failed to remove exception local user owner");
599 + }
600 +
601 + if (bstrRemoteMachineAuthorizedList && *bstrRemoteMachineAuthorizedList)
602 + {
603 + hr = pNetFwRule3->put_RemoteMachineAuthorizedList(bstrRemoteMachineAuthorizedList);
604 + ExitOnFailure(hr, "failed to set exception remote machine authorized list");
605 + }
606 + else if (fUpdateRule)
607 + {
608 + hr = pNetFwRule3->put_RemoteMachineAuthorizedList(NULL);
609 + ExitOnFailure(hr, "failed to remove exception remote machine authorized list");
610 + }
611 +
612 + if (bstrRemoteUserAuthorizedList && *bstrRemoteUserAuthorizedList)
613 + {
614 + hr = pNetFwRule3->put_RemoteUserAuthorizedList(bstrRemoteUserAuthorizedList);
615 + ExitOnFailure(hr, "failed to set exception remote user authorized list");
616 + }
617 + else if (fUpdateRule)
618 + {
619 + hr = pNetFwRule3->put_RemoteUserAuthorizedList(NULL);
620 + ExitOnFailure(hr, "failed to remove exception remote user authorized list");
621 + }
622 +
623 + if (MSI_NULL_INTEGER != attrs.iSecureFlags)
624 + {
625 + hr = pNetFwRule3->put_SecureFlags(attrs.iSecureFlags);
626 + ExitOnFailure(hr, "failed to set exception IPsec secure flags");
627 + }
628 + else if (fUpdateRule)
629 + {
630 + hr = pNetFwRule3->put_SecureFlags(NET_FW_AUTHENTICATE_NONE);
631 + ExitOnFailure(hr, "failed to reset exception IPsec secure flags");
632 + }
633 +
634 +LExit:
635 + ReleaseBSTR(bstrLocalAppPackageId);
636 + ReleaseBSTR(bstrLocalUserAuthorizedList);
637 + ReleaseBSTR(bstrLocalUserOwner);
638 + ReleaseBSTR(bstrRemoteMachineAuthorizedList);
639 + ReleaseBSTR(bstrRemoteUserAuthorizedList);
640 + ReleaseObject(pNetFwRule3);
641 +
642 + return hr;
643 +}
644 +
645 +
646 +/**********************************************************************
647 + UpdateFwRuleObject - update all properties for a basic firewall rule.
648 + Requires Windows Vista / 2008
649 +
650 + **********************************************************************/
651 +static HRESULT UpdateFwRuleObject(
652 + __in INetFwRule* pNetFwRule,
653 + __in BOOL fUpdateRule,
654 + __in FIREWALL_EXCEPTION_ATTRIBUTES const& attrs
655 +)
656 +{
657 + HRESULT hr = S_OK;
658 + BSTR bstrEmpty = NULL;
659 BSTR bstrRemoteAddresses = NULL;
660 + BSTR bstrFile = NULL;
661 BSTR bstrPort = NULL;
662 BSTR bstrDescription = NULL;
288 - INetFwRule* pNetFwRule = NULL;
289 - *ppNetFwRule = NULL;
663 + BSTR bstrGrouping = NULL;
664 + BSTR bstrIcmpTypesAndCodes = NULL;
665 + BSTR bstrInterfaceTypes = NULL;
666 + BSTR bstrLocalAddresses = NULL;
667 + BSTR bstrRemotePort = NULL;
668 + BSTR bstrServiceName = NULL;
669 + VARIANT vInterfaces;
670 + ::VariantInit(&vInterfaces);
671 + LONG iProtocol = 0;
672 +
673 + INetFwRule2* pNetFwRule2 = NULL;
674
675 // convert to BSTRs to make COM happy
676 + bstrEmpty = ::SysAllocString(L"");
677 + ExitOnNull(bstrEmpty, hr, E_OUTOFMEMORY, "failed SysAllocString for empty placeholder");
678 +
679 bstrRemoteAddresses = ::SysAllocString(attrs.pwzRemoteAddresses);
680 ExitOnNull(bstrRemoteAddresses, hr, E_OUTOFMEMORY, "failed SysAllocString for remote addresses");
294 - bstrPort = ::SysAllocString(attrs.pwzPort);
681 + bstrFile = ::SysAllocString(attrs.pwzApplicationName);
682 + ExitOnNull(bstrFile, hr, E_OUTOFMEMORY, "failed SysAllocString for application name");
683 + bstrPort = ::SysAllocString(attrs.pwzLocalPorts);
684 ExitOnNull(bstrPort, hr, E_OUTOFMEMORY, "failed SysAllocString for port");
685 bstrDescription = ::SysAllocString(attrs.pwzDescription);
686 ExitOnNull(bstrDescription, hr, E_OUTOFMEMORY, "failed SysAllocString for description");
687 + bstrGrouping = ::SysAllocString(attrs.pwzGrouping);
688 + ExitOnNull(bstrGrouping, hr, E_OUTOFMEMORY, "failed SysAllocString for grouping");
689 + bstrIcmpTypesAndCodes = ::SysAllocString(attrs.pwzIcmpTypesAndCodes);
690 + ExitOnNull(bstrIcmpTypesAndCodes, hr, E_OUTOFMEMORY, "failed SysAllocString for icmp types and codes");
691 + bstrInterfaceTypes = ::SysAllocString(attrs.pwzInterfaceTypes);
692 + ExitOnNull(bstrInterfaceTypes, hr, E_OUTOFMEMORY, "failed SysAllocString for interface types");
693 + bstrLocalAddresses = ::SysAllocString(attrs.pwzLocalAddresses);
694 + ExitOnNull(bstrLocalAddresses, hr, E_OUTOFMEMORY, "failed SysAllocString for local addresses");
695 + bstrRemotePort = ::SysAllocString(attrs.pwzRemotePorts);
696 + ExitOnNull(bstrRemotePort, hr, E_OUTOFMEMORY, "failed SysAllocString for remote port");
697 + bstrServiceName = ::SysAllocString(attrs.pwzServiceName);
698 + ExitOnNull(bstrServiceName, hr, E_OUTOFMEMORY, "failed SysAllocString for service name");
699 +
700 + if (fUpdateRule)
701 + {
702 + hr = pNetFwRule->get_Protocol(&iProtocol);
703 + ExitOnFailure(hr, "failed to get exception protocol");
704
299 - hr = ::CoCreateInstance(__uuidof(NetFwRule), NULL, CLSCTX_ALL, __uuidof(INetFwRule), (void**)&pNetFwRule);
300 - ExitOnFailure(hr, "failed to create NetFwRule object");
705 + // If you are editing a TCP port rule and converting it into an ICMP rule,
706 + // first delete the ports, change protocol from TCP to ICMP, and then add the ports.
707
302 - hr = pNetFwRule->put_Name(bstrName);
303 - ExitOnFailure(hr, "failed to set exception name");
708 + switch (iProtocol)
709 + {
710 + case NET_FW_IP_PROTOCOL_ANY:
711 + break;
712
305 - hr = pNetFwRule->put_Profiles(static_cast<NET_FW_PROFILE_TYPE2>(attrs.iProfile));
306 - ExitOnFailure(hr, "failed to set exception profile");
713 + case 1: // ICMP
714 + hr = pNetFwRule->put_IcmpTypesAndCodes(NULL);
715 + ExitOnFailure(hr, "failed to remove exception icmp types and codes");
716 + // fall through and reset ports too
717
718 + default:
719 + hr = pNetFwRule->put_LocalPorts(NULL);
720 + ExitOnFailure(hr, "failed to update exception local ports to NULL");
721 +
722 + hr = pNetFwRule->put_RemotePorts(NULL);
723 + ExitOnFailure(hr, "failed to update exception remote ports to NULL");
724 + break;
725 + }
726 + }
727 +
728 + if (MSI_NULL_INTEGER != attrs.iProfile)
729 + {
730 + hr = pNetFwRule->put_Profiles(static_cast<NET_FW_PROFILE_TYPE2> (attrs.iProfile));
731 + ExitOnFailure(hr, "failed to set exception profile");
732 + }
733 + else if (fUpdateRule)
734 + {
735 + hr = pNetFwRule->put_Profiles(NET_FW_PROFILE2_ALL);
736 + ExitOnFailure(hr, "failed to reset exception profile to all");
737 + }
738 +
739 + // The Protocol property must be set before the LocalPorts/RemotePorts properties or an error will be returned.
740 if (MSI_NULL_INTEGER != attrs.iProtocol)
741 {
310 - hr = pNetFwRule->put_Protocol(static_cast<NET_FW_IP_PROTOCOL>(attrs.iProtocol));
742 + hr = pNetFwRule->put_Protocol(static_cast<NET_FW_IP_PROTOCOL> (attrs.iProtocol));
743 ExitOnFailure(hr, "failed to set exception protocol");
744 }
745 + else if (fUpdateRule)
746 + {
747 + if ((bstrPort && *bstrPort) || (bstrRemotePort && *bstrRemotePort))
748 + {
749 + // default protocol is "TCP" in the WiX firewall compiler if a port is specified
750 + hr = pNetFwRule->put_Protocol(NET_FW_IP_PROTOCOL_TCP);
751 + ExitOnFailure(hr, "failed to reset exception protocol to TCP");
752 + }
753 + else
754 + {
755 + hr = pNetFwRule->put_Protocol(NET_FW_IP_PROTOCOL_ANY);
756 + ExitOnFailure(hr, "failed to reset exception protocol to ANY");
757 + }
758 + }
759
760 if (bstrPort && *bstrPort)
761 {
762 hr = pNetFwRule->put_LocalPorts(bstrPort);
317 - ExitOnFailure(hr, "failed to set exception port");
763 + ExitOnFailure(hr, "failed to set exception local ports '%ls'", bstrPort);
764 }
765
766 if (bstrRemoteAddresses && *bstrRemoteAddresses)
@@ -322,122 +768,195 @@ static HRESULT CreateFwRuleObject(
768 hr = pNetFwRule->put_RemoteAddresses(bstrRemoteAddresses);
769 ExitOnFailure(hr, "failed to set exception remote addresses '%ls'", bstrRemoteAddresses);
770 }
771 + else if (fUpdateRule)
772 + {
773 + hr = pNetFwRule->put_RemoteAddresses(bstrEmpty);
774 + ExitOnFailure(hr, "failed to remove exception remote addresses");
775 + }
776
777 if (bstrDescription && *bstrDescription)
778 {
779 hr = pNetFwRule->put_Description(bstrDescription);
780 ExitOnFailure(hr, "failed to set exception description '%ls'", bstrDescription);
781 }
782 + else if (fUpdateRule)
783 + {
784 + hr = pNetFwRule->put_Description(bstrEmpty);
785 + ExitOnFailure(hr, "failed to remove exception description");
786 + }
787
788 if (MSI_NULL_INTEGER != attrs.iDirection)
789 {
790 hr = pNetFwRule->put_Direction(static_cast<NET_FW_RULE_DIRECTION> (attrs.iDirection));
791 ExitOnFailure(hr, "failed to set exception direction");
792 }
793 + else if (fUpdateRule)
794 + {
795 + hr = pNetFwRule->put_Direction(NET_FW_RULE_DIR_IN);
796 + ExitOnFailure(hr, "failed to reset exception direction to in");
797 + }
798
338 - *ppNetFwRule = pNetFwRule;
339 - pNetFwRule = NULL;
799 + if (MSI_NULL_INTEGER != attrs.iAction)
800 + {
801 + hr = pNetFwRule->put_Action(static_cast<NET_FW_ACTION> (attrs.iAction));
802 + ExitOnFailure(hr, "failed to set exception action");
803 + }
804 + else if (fUpdateRule)
805 + {
806 + hr = pNetFwRule->put_Action(NET_FW_ACTION_ALLOW);
807 + ExitOnFailure(hr, "failed to reset exception action to allow");
808 + }
809
341 -LExit:
342 - ReleaseBSTR(bstrRemoteAddresses);
343 - ReleaseBSTR(bstrPort);
344 - ReleaseBSTR(bstrDescription);
345 - ReleaseObject(pNetFwRule);
810 + if (bstrFile && *bstrFile)
811 + {
812 + hr = pNetFwRule->put_ApplicationName(bstrFile);
813 + ExitOnFailure(hr, "failed to set exception application name");
814 + }
815 + else if (fUpdateRule)
816 + {
817 + hr = pNetFwRule->put_ApplicationName(NULL);
818 + ExitOnFailure(hr, "failed to remove exception application name");
819 + }
820
347 - return hr;
348 -}
821 + if (MSI_NULL_INTEGER != attrs.iEdgeTraversal)
822 + {
823 + switch (attrs.iEdgeTraversal)
824 + {
825 + default:
826 + hr = pNetFwRule->put_EdgeTraversal(NET_FW_EDGE_TRAVERSAL_TYPE_DENY != attrs.iEdgeTraversal ? VARIANT_TRUE : VARIANT_FALSE);
827 + ExitOnFailure(hr, "failed to set exception edge traversal");
828 + break;
829
350 -/******************************************************************
351 - AddApplicationException
830 + // handled by put_EdgeTraversalOptions
831 + case NET_FW_EDGE_TRAVERSAL_TYPE_DEFER_TO_APP:
832 + case NET_FW_EDGE_TRAVERSAL_TYPE_DEFER_TO_USER:
833 + break;
834 + }
835 + }
836 + else if (fUpdateRule)
837 + {
838 + hr = pNetFwRule->put_EdgeTraversal(VARIANT_FALSE);
839 + ExitOnFailure(hr, "failed to remove exception edge traversal");
840 + }
841
353 -********************************************************************/
354 -static HRESULT AddApplicationException(
355 - __in FIREWALL_EXCEPTION_ATTRIBUTES const& attrs,
356 - __in BOOL fIgnoreFailures
357 - )
358 -{
359 - HRESULT hr = S_OK;
360 - BSTR bstrFile = NULL;
361 - BSTR bstrName = NULL;
362 - INetFwRules* pNetFwRules = NULL;
363 - INetFwRule* pNetFwRule = NULL;
842 + // enable even when iEnabled == MSI_NULL_INTEGER
843 + hr = pNetFwRule->put_Enabled(attrs.iEnabled ? VARIANT_TRUE : VARIANT_FALSE);
844 + ExitOnFailure(hr, "failed to set exception enabled flag");
845
365 - // convert to BSTRs to make COM happy
366 - bstrFile = ::SysAllocString(attrs.pwzProgram);
367 - ExitOnNull(bstrFile, hr, E_OUTOFMEMORY, "failed SysAllocString for path");
368 - bstrName = ::SysAllocString(attrs.pwzName);
369 - ExitOnNull(bstrName, hr, E_OUTOFMEMORY, "failed SysAllocString for name");
846 + if (bstrGrouping && *bstrGrouping)
847 + {
848 + hr = pNetFwRule->put_Grouping(bstrGrouping);
849 + ExitOnFailure(hr, "failed to set exception grouping '%ls'", bstrGrouping);
850 + }
851 + else if (fUpdateRule)
852 + {
853 + hr = pNetFwRule->put_Grouping(bstrEmpty);
854 + ExitOnFailure(hr, "failed to remove exception grouping");
855 + }
856
371 - // get the collection of firewall rules
372 - hr = GetFirewallRules(fIgnoreFailures, &pNetFwRules);
373 - ExitOnFailure(hr, "failed to get firewall rules object");
374 - if (S_FALSE == hr) // user or package author chose to ignore missing firewall
857 + if (bstrIcmpTypesAndCodes && *bstrIcmpTypesAndCodes)
858 {
376 - ExitFunction();
859 + hr = pNetFwRule->put_IcmpTypesAndCodes(bstrIcmpTypesAndCodes);
860 + ExitOnFailure(hr, "failed to set exception icmp types and codes '%ls'", bstrIcmpTypesAndCodes);
861 }
862
379 - // try to find it (i.e., support reinstall)
380 - hr = pNetFwRules->Item(bstrName, &pNetFwRule);
381 - if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
863 + hr = GetFwRuleInterfaces(attrs, vInterfaces);
864 + ExitOnFailure(hr, "failed to prepare exception interfaces '%ls'", attrs.pwzInterfaces);
865 +
866 + if (attrs.pwzInterfaces && *attrs.pwzInterfaces)
867 {
383 - hr = CreateFwRuleObject(bstrName, attrs, &pNetFwRule);
384 - ExitOnFailure(hr, "failed to create FwRule object");
868 + hr = pNetFwRule->put_Interfaces(vInterfaces);
869 + ExitOnFailure(hr, "failed to set exception interfaces '%ls'", attrs.pwzInterfaces);
870 + }
871 + else if (fUpdateRule)
872 + {
873 + hr = pNetFwRule->put_Interfaces(vInterfaces);
874 + ExitOnFailure(hr, "failed to remove exception interfaces");
875 + }
876
386 - // set edge traversal to true
387 - hr = pNetFwRule->put_EdgeTraversal(VARIANT_TRUE);
388 - ExitOnFailure(hr, "failed to set application exception edgetraversal property");
389 -
390 - // set path
391 - hr = pNetFwRule->put_ApplicationName(bstrFile);
392 - ExitOnFailure(hr, "failed to set application name");
393 -
394 - // enable it
395 - hr = pNetFwRule->put_Enabled(VARIANT_TRUE);
396 - ExitOnFailure(hr, "failed to to enable application exception");
397 -
398 - // add it to the list of authorized apps
399 - hr = pNetFwRules->Add(pNetFwRule);
400 - ExitOnFailure(hr, "failed to add app to the authorized apps list");
877 + if (bstrInterfaceTypes && *bstrInterfaceTypes)
878 + {
879 + hr = pNetFwRule->put_InterfaceTypes(bstrInterfaceTypes);
880 + ExitOnFailure(hr, "failed to set exception interface types '%ls'", bstrInterfaceTypes);
881 }
402 - else
882 + else if (fUpdateRule)
883 {
404 - // we found an existing app exception (if we succeeded, that is)
405 - ExitOnFailure(hr, "failed trying to find existing app");
406 -
407 - // enable it (just in case it was disabled)
408 - pNetFwRule->put_Enabled(VARIANT_TRUE);
884 + hr = pNetFwRule->put_InterfaceTypes(bstrEmpty);
885 + ExitOnFailure(hr, "failed to remove exception interface types");
886 + }
887 +
888 + if (bstrLocalAddresses && *bstrLocalAddresses)
889 + {
890 + hr = pNetFwRule->put_LocalAddresses(bstrLocalAddresses);
891 + ExitOnFailure(hr, "failed to set exception local addresses '%ls'", bstrLocalAddresses);
892 + }
893 + else if (fUpdateRule)
894 + {
895 + hr = pNetFwRule->put_LocalAddresses(bstrEmpty);
896 + ExitOnFailure(hr, "failed to remove exception local addresses");
897 + }
898 +
899 + if (bstrRemotePort && *bstrRemotePort)
900 + {
901 + hr = pNetFwRule->put_RemotePorts(bstrRemotePort);
902 + ExitOnFailure(hr, "failed to set exception remote ports '%ls'", bstrRemotePort);
903 + }
904 +
905 + if (bstrServiceName && *bstrServiceName)
906 + {
907 + hr = pNetFwRule->put_ServiceName(bstrServiceName);
908 + ExitOnFailure(hr, "failed to set exception service name '%ls'", bstrServiceName);
909 + }
910 + else if (fUpdateRule)
911 + {
912 + hr = pNetFwRule->put_ServiceName(NULL);
913 + ExitOnFailure(hr, "failed to remove exception service name");
914 }
915
916 LExit:
412 - ReleaseBSTR(bstrName);
917 + ReleaseBSTR(bstrRemoteAddresses);
918 ReleaseBSTR(bstrFile);
414 - ReleaseObject(pNetFwRules);
415 - ReleaseObject(pNetFwRule);
919 + ReleaseBSTR(bstrPort);
920 + ReleaseBSTR(bstrDescription);
921 + ReleaseBSTR(bstrGrouping);
922 + ReleaseBSTR(bstrIcmpTypesAndCodes);
923 + ReleaseBSTR(bstrInterfaceTypes);
924 + ReleaseBSTR(bstrLocalAddresses);
925 + ReleaseBSTR(bstrRemotePort);
926 + ReleaseBSTR(bstrServiceName);
927 + ReleaseVariant(vInterfaces);
928 + ReleaseObject(pNetFwRule2);
929
417 - return fIgnoreFailures ? S_OK : hr;
930 + return hr;
931 }
932
420 -/******************************************************************
421 - AddPortException
933 +
934 +/*******************************************************************
935 + AddFirewallException
936
937 ********************************************************************/
424 -static HRESULT AddPortException(
938 +static HRESULT AddFirewallException(
939 __in FIREWALL_EXCEPTION_ATTRIBUTES const& attrs,
940 __in BOOL fIgnoreFailures
427 - )
941 +)
942 {
943 HRESULT hr = S_OK;
944 BSTR bstrName = NULL;
945 INetFwRules* pNetFwRules = NULL;
946 INetFwRule* pNetFwRule = NULL;
947
948 + BOOL fIgnoreUpdates = feaIgnoreUpdates == (attrs.iAttributes & feaIgnoreUpdates);
949 + BOOL fEnableOnUpdate = feaEnableOnUpdate == (attrs.iAttributes & feaEnableOnUpdate);
950 + BOOL fAddINetFwRule2 = feaAddINetFwRule2 == (attrs.iAttributes & feaAddINetFwRule2);
951 + BOOL fAddINetFwRule3 = feaAddINetFwRule3 == (attrs.iAttributes & feaAddINetFwRule3);
952 +
953 // convert to BSTRs to make COM happy
954 bstrName = ::SysAllocString(attrs.pwzName);
955 ExitOnNull(bstrName, hr, E_OUTOFMEMORY, "failed SysAllocString for name");
956
957 // get the collection of firewall rules
958 hr = GetFirewallRules(fIgnoreFailures, &pNetFwRules);
440 - ExitOnFailure(hr, "failed to get firewall rules object");
959 + ExitOnFailure(hr, "failed to get firewall exception object");
960 if (S_FALSE == hr) // user or package author chose to ignore missing firewall
961 {
962 ExitFunction();
@@ -447,24 +966,56 @@ static HRESULT AddPortException(
966 hr = pNetFwRules->Item(bstrName, &pNetFwRule);
967 if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
968 {
450 - hr = CreateFwRuleObject(bstrName, attrs, &pNetFwRule);
451 - ExitOnFailure(hr, "failed to create FwRule object");
969 + hr = CreateFwRuleObject(bstrName, &pNetFwRule);
970 + ExitOnFailure(hr, "failed to create FwRule object '%ls'", attrs.pwzName);
971
453 - // enable it
454 - hr = pNetFwRule->put_Enabled(VARIANT_TRUE);
455 - ExitOnFailure(hr, "failed to to enable port exception");
972 + // set attributes of the new firewall rule
973 + hr = UpdateFwRuleObject(pNetFwRule, FALSE, attrs);
974 + ExitOnFailure(hr, "failed to create INetFwRule firewall exception '%ls'", attrs.pwzName);
975 +
976 + if (fAddINetFwRule2)
977 + {
978 + hr = UpdateFwRule2Object(pNetFwRule, FALSE, attrs);
979 + ExitOnFailure(hr, "failed to create INetFwRule2 firewall exception '%ls'", attrs.pwzName);
980 + }
981 +
982 + if (fAddINetFwRule3)
983 + {
984 + hr = UpdateFwRule3Object(pNetFwRule, FALSE, attrs);
985 + ExitOnFailure(hr, "failed to create INetFwRule3 firewall exception '%ls'", attrs.pwzName);
986 + }
987
457 - // add it to the list of authorized ports
988 hr = pNetFwRules->Add(pNetFwRule);
459 - ExitOnFailure(hr, "failed to add app to the authorized ports list");
989 + ExitOnFailure(hr, "failed to add firewall exception '%ls' to the list", attrs.pwzName);
990 }
991 else
992 {
463 - // we found an existing port exception (if we succeeded, that is)
464 - ExitOnFailure(hr, "failed trying to find existing port rule");
993 + // we found an existing firewall rule (if we succeeded, that is)
994 + ExitOnFailure(hr, "failed trying to find existing firewall exception '%ls'", attrs.pwzName);
995 +
996 + if (fEnableOnUpdate)
997 + {
998 + hr = pNetFwRule->put_Enabled(VARIANT_TRUE);
999 + ExitOnFailure(hr, "failed to enable existing firewall exception '%ls'", attrs.pwzName);
1000 + }
1001 + else if (!fIgnoreUpdates)
1002 + {
1003 + // overwrite attributes of the existing firewall rule
1004 + hr = UpdateFwRuleObject(pNetFwRule, TRUE, attrs);
1005 + ExitOnFailure(hr, "failed to update INetFwRule firewall exception '%ls'", attrs.pwzName);
1006
466 - // enable it (just in case it was disabled)
467 - pNetFwRule->put_Enabled(VARIANT_TRUE);
1007 + if (fAddINetFwRule2)
1008 + {
1009 + hr = UpdateFwRule2Object(pNetFwRule, TRUE, attrs);
1010 + ExitOnFailure(hr, "failed to update INetFwRule2 firewall exception '%ls'", attrs.pwzName);
1011 + }
1012 +
1013 + if (fAddINetFwRule3)
1014 + {
1015 + hr = UpdateFwRule3Object(pNetFwRule, TRUE, attrs);
1016 + ExitOnFailure(hr, "failed to update INetFwRule3 firewall exception '%ls'", attrs.pwzName);
1017 + }
1018 + }
1019 }
1020
1021 LExit:
@@ -475,14 +1026,15 @@ LExit:
1026 return fIgnoreFailures ? S_OK : hr;
1027 }
1028
478 -/******************************************************************
1029 +
1030 +/*******************************************************************
1031 RemoveException - Removes all exception rules with the given name.
1032
1033 ********************************************************************/
1034 static HRESULT RemoveException(
1035 __in LPCWSTR wzName,
1036 __in BOOL fIgnoreFailures
485 - )
1037 +)
1038 {
1039 HRESULT hr = S_OK;;
1040 INetFwRules* pNetFwRules = NULL;
@@ -500,7 +1052,7 @@ static HRESULT RemoveException(
1052 }
1053
1054 hr = pNetFwRules->Remove(bstrName);
503 - ExitOnFailure(hr, "failed to remove firewall rule");
1055 + ExitOnFailure(hr, "failed to remove firewall exception for name %ls", wzName);
1056
1057 LExit:
1058 ReleaseBSTR(bstrName);
@@ -509,20 +1061,20 @@ LExit:
1061 return fIgnoreFailures ? S_OK : hr;
1062 }
1063
512 -/******************************************************************
513 - ExecFirewallExceptions - deferred custom action entry point to
1064 +
1065 +/*******************************************************************
1066 + ExecFirewallExceptions - deferred custom action entry point to
1067 register and remove firewall exceptions.
1068
1069 ********************************************************************/
1070 extern "C" UINT __stdcall ExecFirewallExceptions(
1071 __in MSIHANDLE hInstall
519 - )
1072 +)
1073 {
1074 HRESULT hr = S_OK;
1075 LPWSTR pwz = NULL;
1076 LPWSTR pwzCustomActionData = NULL;
1077 int iTodo = WCA_TODO_UNKNOWN;
525 - int iTarget = fetUnknown;
1078
1079 FIREWALL_EXCEPTION_ATTRIBUTES attrs = { 0 };
1080
@@ -530,7 +1082,7 @@ extern "C" UINT __stdcall ExecFirewallExceptions(
1082 hr = WcaInitialize(hInstall, "ExecFirewallExceptions");
1083 ExitOnFailure(hr, "failed to initialize");
1084
533 - hr = WcaGetProperty( L"CustomActionData", &pwzCustomActionData);
1085 + hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData);
1086 ExitOnFailure(hr, "failed to get CustomActionData");
1087 WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData);
1088
@@ -569,60 +1121,82 @@ extern "C" UINT __stdcall ExecFirewallExceptions(
1121 ExitOnFailure(hr, "failed to read attributes from custom action data");
1122 BOOL fIgnoreFailures = feaIgnoreFailures == (attrs.iAttributes & feaIgnoreFailures);
1123
572 - hr = WcaReadIntegerFromCaData(&pwz, &iTarget);
573 - ExitOnFailure(hr, "failed to read target from custom action data");
1124 + hr = WcaReadStringFromCaData(&pwz, &attrs.pwzApplicationName);
1125 + ExitOnFailure(hr, "failed to read file path from custom action data");
1126
575 - if (iTarget == fetApplication)
576 - {
577 - hr = WcaReadStringFromCaData(&pwz, &attrs.pwzProgram);
578 - ExitOnFailure(hr, "failed to read file path from custom action data");
579 - }
580 -
581 - hr = WcaReadStringFromCaData(&pwz, &attrs.pwzPort);
1127 + hr = WcaReadStringFromCaData(&pwz, &attrs.pwzLocalPorts);
1128 ExitOnFailure(hr, "failed to read port from custom action data");
1129 +
1130 hr = WcaReadIntegerFromCaData(&pwz, &attrs.iProtocol);
1131 ExitOnFailure(hr, "failed to read protocol from custom action data");
1132 +
1133 hr = WcaReadStringFromCaData(&pwz, &attrs.pwzDescription);
1134 ExitOnFailure(hr, "failed to read protocol from custom action data");
1135 +
1136 hr = WcaReadIntegerFromCaData(&pwz, &attrs.iDirection);
1137 ExitOnFailure(hr, "failed to read direction from custom action data");
1138
590 - switch (iTarget)
591 - {
592 - case fetPort:
593 - switch (iTodo)
594 - {
595 - case WCA_TODO_INSTALL:
596 - case WCA_TODO_REINSTALL:
597 - WcaLog(LOGMSG_STANDARD, "Installing firewall exception %ls on port %ls, protocol %d", attrs.pwzName, attrs.pwzPort, attrs.iProtocol);
598 - hr = AddPortException(attrs, fIgnoreFailures);
599 - ExitOnFailure(hr, "failed to add/update port exception for name '%ls' on port %ls, protocol %d", attrs.pwzName, attrs.pwzPort, attrs.iProtocol);
600 - break;
1139 + hr = WcaReadIntegerFromCaData(&pwz, &attrs.iAction);
1140 + ExitOnFailure(hr, "failed to read action from custom action data");
1141
602 - case WCA_TODO_UNINSTALL:
603 - WcaLog(LOGMSG_STANDARD, "Uninstalling firewall exception %ls on port %ls, protocol %d", attrs.pwzName, attrs.pwzPort, attrs.iProtocol);
604 - hr = RemoveException(attrs.pwzName, fIgnoreFailures);
605 - ExitOnFailure(hr, "failed to remove port exception for name '%ls' on port %ls, protocol %d", attrs.pwzName, attrs.pwzPort, attrs.iProtocol);
606 - break;
607 - }
608 - break;
1142 + hr = WcaReadIntegerFromCaData(&pwz, &attrs.iEdgeTraversal);
1143 + ExitOnFailure(hr, "failed to read edge traversal from custom action data");
1144
610 - case fetApplication:
611 - switch (iTodo)
612 - {
613 - case WCA_TODO_INSTALL:
614 - case WCA_TODO_REINSTALL:
615 - WcaLog(LOGMSG_STANDARD, "Installing firewall exception %ls (%ls)", attrs.pwzName, attrs.pwzProgram);
616 - hr = AddApplicationException(attrs, fIgnoreFailures);
617 - ExitOnFailure(hr, "failed to add/update application exception for name '%ls', file '%ls'", attrs.pwzName, attrs.pwzProgram);
618 - break;
1145 + hr = WcaReadIntegerFromCaData(&pwz, &attrs.iEnabled);
1146 + ExitOnFailure(hr, "failed to read enabled flag from custom action data");
1147
620 - case WCA_TODO_UNINSTALL:
621 - WcaLog(LOGMSG_STANDARD, "Uninstalling firewall exception %ls (%ls)", attrs.pwzName, attrs.pwzProgram);
622 - hr = RemoveException(attrs.pwzName, fIgnoreFailures);
623 - ExitOnFailure(hr, "failed to remove application exception for name '%ls', file '%ls'", attrs.pwzName, attrs.pwzProgram);
624 - break;
625 - }
1148 + hr = WcaReadStringFromCaData(&pwz, &attrs.pwzGrouping);
1149 + ExitOnFailure(hr, "failed to read grouping from custom action data");
1150 +
1151 + hr = WcaReadStringFromCaData(&pwz, &attrs.pwzIcmpTypesAndCodes);
1152 + ExitOnFailure(hr, "failed to read icmp types and codes from custom action data");
1153 +
1154 + hr = WcaReadStringFromCaData(&pwz, &attrs.pwzInterfaces);
1155 + ExitOnFailure(hr, "failed to read interfaces from custom action data");
1156 +
1157 + hr = WcaReadStringFromCaData(&pwz, &attrs.pwzInterfaceTypes);
1158 + ExitOnFailure(hr, "failed to read interface types from custom action data");
1159 +
1160 + hr = WcaReadStringFromCaData(&pwz, &attrs.pwzLocalAddresses);
1161 + ExitOnFailure(hr, "failed to read local addresses from custom action data");
1162 +
1163 + hr = WcaReadStringFromCaData(&pwz, &attrs.pwzRemotePorts);
1164 + ExitOnFailure(hr, "failed to read remote port from custom action data");
1165 +
1166 + hr = WcaReadStringFromCaData(&pwz, &attrs.pwzServiceName);
1167 + ExitOnFailure(hr, "failed to read service name from custom action data");
1168 +
1169 + hr = WcaReadStringFromCaData(&pwz, &attrs.pwzLocalAppPackageId);
1170 + ExitOnFailure(hr, "failed to read local app package id from custom action data");
1171 +
1172 + hr = WcaReadStringFromCaData(&pwz, &attrs.pwzLocalUserAuthorizedList);
1173 + ExitOnFailure(hr, "failed to read local user authorized list from custom action data");
1174 +
1175 + hr = WcaReadStringFromCaData(&pwz, &attrs.pwzLocalUserOwner);
1176 + ExitOnFailure(hr, "failed to read local user owner from custom action data");
1177 +
1178 + hr = WcaReadStringFromCaData(&pwz, &attrs.pwzRemoteMachineAuthorizedList);
1179 + ExitOnFailure(hr, "failed to read remote machine authorized list from custom action data");
1180 +
1181 + hr = WcaReadStringFromCaData(&pwz, &attrs.pwzRemoteUserAuthorizedList);
1182 + ExitOnFailure(hr, "failed to read remote user authorized list from custom action data");
1183 +
1184 + hr = WcaReadIntegerFromCaData(&pwz, &attrs.iSecureFlags);
1185 + ExitOnFailure(hr, "failed to read exception secure flags from custom action data");
1186 +
1187 + switch (iTodo)
1188 + {
1189 + case WCA_TODO_INSTALL:
1190 + case WCA_TODO_REINSTALL:
1191 + WcaLog(LOGMSG_STANDARD, "Installing firewall exception %ls", attrs.pwzName);
1192 + hr = AddFirewallException(attrs, fIgnoreFailures);
1193 + ExitOnFailure(hr, "failed to add/update firewall exception for name '%ls'", attrs.pwzName);
1194 + break;
1195 +
1196 + case WCA_TODO_UNINSTALL:
1197 + WcaLog(LOGMSG_STANDARD, "Uninstalling firewall exception %ls", attrs.pwzName);
1198 + hr = RemoveException(attrs.pwzName, fIgnoreFailures);
1199 + ExitOnFailure(hr, "failed to remove firewall exception");
1200 break;
1201 }
1202 }
@@ -631,9 +1205,21 @@ LExit:
1205 ReleaseStr(pwzCustomActionData);
1206 ReleaseStr(attrs.pwzName);
1207 ReleaseStr(attrs.pwzRemoteAddresses);
634 - ReleaseStr(attrs.pwzProgram);
635 - ReleaseStr(attrs.pwzPort);
1208 + ReleaseStr(attrs.pwzApplicationName);
1209 + ReleaseStr(attrs.pwzLocalPorts);
1210 ReleaseStr(attrs.pwzDescription);
1211 + ReleaseStr(attrs.pwzGrouping);
1212 + ReleaseStr(attrs.pwzIcmpTypesAndCodes);
1213 + ReleaseStr(attrs.pwzInterfaces);
1214 + ReleaseStr(attrs.pwzInterfaceTypes);
1215 + ReleaseStr(attrs.pwzLocalAddresses);
1216 + ReleaseStr(attrs.pwzRemotePorts);
1217 + ReleaseStr(attrs.pwzServiceName);
1218 + ReleaseStr(attrs.pwzLocalAppPackageId);
1219 + ReleaseStr(attrs.pwzLocalUserAuthorizedList);
1220 + ReleaseStr(attrs.pwzLocalUserOwner);
1221 + ReleaseStr(attrs.pwzRemoteMachineAuthorizedList);
1222 + ReleaseStr(attrs.pwzRemoteUserAuthorizedList);
1223 ::CoUninitialize();
1224
1225 return WcaFinalize(FAILED(hr) ? ERROR_INSTALL_FAILURE : ERROR_SUCCESS);
src/ext/Firewall/test/WixToolsetTest.Firewall/FirewallExtensionFixture.cs
+457 -28
@@ -2,6 +2,7 @@
2
3 namespace WixToolsetTest.Firewall
4 {
5 + using System.Data;
6 using System.IO;
7 using System.Linq;
8 using System.Xml.Linq;
@@ -27,12 +28,27 @@ namespace WixToolsetTest.Firewall
28 "CustomAction:Wix5RollbackFirewallExceptionsUninstall_X86\t3329\tWix5FWCA_X86\tExecFirewallExceptions\t",
29 "CustomAction:Wix5SchedFirewallExceptionsInstall_X86\t1\tWix5FWCA_X86\tSchedFirewallExceptionsInstall\t",
30 "CustomAction:Wix5SchedFirewallExceptionsUninstall_X86\t1\tWix5FWCA_X86\tSchedFirewallExceptionsUninstall\t",
30 - "Wix5FirewallException:ExampleFirewall\tExampleApp\t*\t42\t6\t[#filNdJBJmq3UCUIwmXS8x21aAsvqzk]\t0\t2147483647\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tAn app-based firewall exception\t1",
31 - "Wix5FirewallException:fex_ZpDsnKyHlYiA24JHzvFxm3uLZ8\tExampleDefaultGatewayScope\tDefaultGateway\t4432\t6\t\t0\t2\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tdefaultGateway scope firewall exception\t1",
32 - "Wix5FirewallException:fex6bkfWwpiRGI.wVFx0T7W4LXIHxU\tExampleDHCPScope\tdhcp\t\t211\ttest.exe\t0\t4\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tDHCP scope firewall exception\t1",
33 - "Wix5FirewallException:fex70IVsYNnbwiHQrEepmdTPKH8XYs\tExamplePort\tLocalSubnet\t42\t6\t\t0\t2147483647\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tA port-based firewall exception\t2",
34 - "Wix5FirewallException:fexXxaXCXXFh.UxO_BjmZxi1B1du_Q\tExampleWINSScope\twins\t6573\t6\t\t0\t1\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tWINS scope firewall exception\t1",
35 - "Wix5FirewallException:fexxY71H2ZBkPalv7uid1Yy4qaA_lA\tExampleDNSScope\tdns\t356\t17\t\t0\t2147483647\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tDNS scope firewall exception\t1",
31 + "Wix5FirewallException:ExampleFirewall\tExampleApp\t*\t42\t6\t[#filNdJBJmq3UCUIwmXS8x21aAsvqzk]\t2\t-2147483648\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tAn app-based firewall exception\t1\t-2147483648\t-2147483648\t-2147483648\t\t\t\t\t\t\t\t\t\t\t\t\t-2147483648",
32 + "Wix5FirewallException:fex.BGtyMRGAhxb2hG.49JvWYz7fM0\tLocalScopeExample2\t*\t\t-2147483648\t\t0\t-2147483648\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tRule with local scope property\t1\t-2147483648\t-2147483648\t-2147483648\t\t\t\t\t[LOCALSCOPE_PROP]\t\t\t\t\t\t\t\t-2147483648",
33 + "Wix5FirewallException:fex0HTxATWjpC2PCoY6DB7f2D1WaKU\tLocalScopeExample1\t*\t\t-2147483648\t\t0\t-2147483648\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tSimple rule with local scope\t1\t-2147483648\t-2147483648\t-2147483648\t\t\t\t\tLocalSubnet\t\t\t\t\t\t\t\t-2147483648",
34 + "Wix5FirewallException:fex4FeP470wYcFpw.g7fbIKiLnZPzg\tExampleDNSScope\tdns\t356\t17\t\t0\t-2147483648\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tDNS scope firewall exception\t1\t-2147483648\t-2147483648\t-2147483648\t\t\t\t\t\t\t\t\t\t\t\t\t-2147483648",
35 + "Wix5FirewallException:fex4zTcT0Iwu3dUtHIHXD5qfymvpcM\tdefertouser\t\t\t-2147483648\tfw.exe\t8\t-2147483648\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tDefer to user edge traversal\t1\t-2147483648\t3\t-2147483648\t\t\t\t\t\t\t\t\t\t\t\t\t-2147483648",
36 + "Wix5FirewallException:fex8vMfBplrod4daEz3PqDTeX6olGE\tExampleDefaultGatewayScope\tDefaultGateway\t4432\t6\t\t0\t2\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tdefaultGateway scope firewall exception\t1\t-2147483648\t-2147483648\t-2147483648\t\t\t\t\t\t\t\t\t\t\t\t\t-2147483648",
37 + "Wix5FirewallException:fexAMmHzFDyQmubTOnKS1Cn0Y3q_Ug\tINetFwRule3 properties\t*\t\t-2147483648\t\t16\t-2147483648\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tINetFwRule3 passed via properties\t1\t-2147483648\t-2147483648\t-2147483648\t\t\t\t\t\t\t\t[PROP1]\t[PROP2]\t[PROP3]\t[PROP4]\t[PROP5]\t[PROP6]",
38 + "Wix5FirewallException:fexArlOkFR7CAwVZ2wk8yNdiREydu0\tRemotePortExample2\t\t\t6\tfw.exe\t0\t-2147483648\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tRule with remote port property\t1\t-2147483648\t-2147483648\t-2147483648\t\t\t\t\t\t[REMOTEPORT_PROP]\t\t\t\t\t\t\t-2147483648",
39 + "Wix5FirewallException:fexaUTe2tRRcSYrPUTn44DAZhE.40Q\tExamplePort\tLocalSubnet\t42\t6\t\t4\t-2147483648\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tA port-based firewall exception\t2\t-2147483648\t-2147483648\t-2147483648\t\t\t\t\t\t\t\t\t\t\t\t\t-2147483648",
40 + "Wix5FirewallException:fexD6w20c5HfNi4l1vHFj_eet4cC8I\tExampleWINSScope\twins\t6573\t6\t\t0\t1\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tWINS scope firewall exception\t1\t-2147483648\t-2147483648\t-2147483648\t\t\t\t\t\t\t\t\t\t\t\t\t-2147483648",
41 + "Wix5FirewallException:fexeD3yox6fMflfRy7sDwSN2CMCS2s\tExampleService\t\t12000\t6\t%windir%\\system32\\svchost.exe\t0\t-2147483648\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tA port-based service exception\t1\t-2147483648\t-2147483648\t-2147483648\t\t\t\t\tDHCP,WINS\t\tftpsrv\t\t\t\t\t\t-2147483648",
42 + "Wix5FirewallException:fexeok6aI2_AlclZggec4d8PBLFXLw\tinterface property\t\t54671\t6\t\t0\t-2147483648\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tInterfaces with property\t1\t-2147483648\t-2147483648\t-2147483648\t\t\t[INTERFACE_PROPERTY]\t\t\t\t\t\t\t\t\t\t-2147483648",
43 + "Wix5FirewallException:fexEPvcf4iexD1mVQdvxm7tD02nZEc\tICMPExample1\t\t\t2\t\t0\t-2147483648\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tSimple ICMP rule\t1\t-2147483648\t-2147483648\t-2147483648\t\t4:*,9:*,12:*\t\t\t\t\t\t\t\t\t\t\t-2147483648",
44 + "Wix5FirewallException:fexfzjTQsWwZkHQpObtl0XaUosfcRk\tGroupingExample1\t\t\t-2147483648\tfw.exe\t0\t-2147483648\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tSimple rule with grouping\t1\t-2147483648\t-2147483648\t-2147483648\t@yourresources.dll,-1005\t\t\t\t\t\t\t\t\t\t\t\t-2147483648",
45 + "Wix5FirewallException:fexHx2xbwZYzAi0oYp4YGWevJQs5eM\tRemotePortExample1\t*\t\t6\t\t0\t-2147483648\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tSimple rule with remote port\t1\t-2147483648\t-2147483648\t-2147483648\t\t\t\t\t\t34560\t\t\t\t\t\t\t-2147483648",
46 + "Wix5FirewallException:fexpWUzK53RVnaluW36gSmphPRY8VY\tExampleDHCPScope\tdhcp\t\t211\ttest.exe\t0\t4\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tDHCP scope firewall exception\t1\t-2147483648\t-2147483648\t-2147483648\t\t\t\t\t\t\t\t\t\t\t\t\t-2147483648",
47 + "Wix5FirewallException:fexuanTga5xaaFzr9JsAnUmpCNediw\tICMPExample2\t\t\t2\t\t0\t-2147483648\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tRule with ICMP property\t1\t-2147483648\t-2147483648\t-2147483648\t\t[ICMP_PROP]\t\t\t\t\t\t\t\t\t\t\t-2147483648",
48 + "Wix5FirewallException:fexv60s7u2Dmd1imH5vEFYKPgEWhG4\tinterface nested\t127.0.0.1\t54671\t6\t\t0\t-2147483648\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tInterfaces with nested elements\t1\t-2147483648\t-2147483648\t-2147483648\t\t\tWi-Fi|Local Area Connection\t\t\t\t\t\t\t\t\t\t-2147483648",
49 + "Wix5FirewallException:fexVr6uHcOCak5MHuTLwujjh_oKtbI\tGroupingExample2\t\t8732\t6\t\t0\t-2147483648\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tRule with grouping property\t1\t-2147483648\t-2147483648\t-2147483648\t[GROUPING_PROP]\t\t\t\t\t\t\t\t\t\t\t\t-2147483648",
50 + "Wix5FirewallException:fexwjf4OTFVE9SNiC4goVxBA6ENJBE\tINetFwRule3 values\t*\t\t-2147483648\t\t16\t-2147483648\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tSimple INetFwRule3 values\t1\t-2147483648\t-2147483648\t-2147483648\t\t\t\t\t\t\t\tS-1-15-2-1239072475-3687740317-1842961305-3395936705-4023953123-1525404051-2779347315\tO:LSD:(A;;CC;;;S-1-5-84-0-0-0-0-0)\tS-1-5-21-1898747406-2352535518-1247798438-1914\t127.0.0.1\tO:LSD:(A;;CC;;;S-1-5-84-0-0-0-0-0)\t3",
51 + "Wix5FirewallException:ServiceInstall.nested\tExampleNestedService\tLocalSubnet\t3546-7890\t6\t\t1\t-2147483648\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tA port-based firewall exception for a windows service\t1\t-2147483648\t-2147483648\t-2147483648\t\t\t\tLan,Wireless\t\t\tsvc1\t\t\t\t\t\t-2147483648",
52 }, results);
53 }
54
@@ -51,12 +67,69 @@ namespace WixToolsetTest.Firewall
67 "CustomAction:Wix5RollbackFirewallExceptionsUninstall_A64\t3329\tWix5FWCA_A64\tExecFirewallExceptions\t",
68 "CustomAction:Wix5SchedFirewallExceptionsInstall_A64\t1\tWix5FWCA_A64\tSchedFirewallExceptionsInstall\t",
69 "CustomAction:Wix5SchedFirewallExceptionsUninstall_A64\t1\tWix5FWCA_A64\tSchedFirewallExceptionsUninstall\t",
54 - "Wix5FirewallException:ExampleFirewall\tExampleApp\t*\t42\t6\t[#filNdJBJmq3UCUIwmXS8x21aAsvqzk]\t0\t2147483647\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tAn app-based firewall exception\t1",
55 - "Wix5FirewallException:fex_ZpDsnKyHlYiA24JHzvFxm3uLZ8\tExampleDefaultGatewayScope\tDefaultGateway\t4432\t6\t\t0\t2\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tdefaultGateway scope firewall exception\t1",
56 - "Wix5FirewallException:fex6bkfWwpiRGI.wVFx0T7W4LXIHxU\tExampleDHCPScope\tdhcp\t\t211\ttest.exe\t0\t4\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tDHCP scope firewall exception\t1",
57 - "Wix5FirewallException:fex70IVsYNnbwiHQrEepmdTPKH8XYs\tExamplePort\tLocalSubnet\t42\t6\t\t0\t2147483647\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tA port-based firewall exception\t2",
58 - "Wix5FirewallException:fexXxaXCXXFh.UxO_BjmZxi1B1du_Q\tExampleWINSScope\twins\t6573\t6\t\t0\t1\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tWINS scope firewall exception\t1",
59 - "Wix5FirewallException:fexxY71H2ZBkPalv7uid1Yy4qaA_lA\tExampleDNSScope\tdns\t356\t17\t\t0\t2147483647\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tDNS scope firewall exception\t1",
70 + "Wix5FirewallException:ExampleFirewall\tExampleApp\t*\t42\t6\t[#filNdJBJmq3UCUIwmXS8x21aAsvqzk]\t2\t-2147483648\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tAn app-based firewall exception\t1\t-2147483648\t-2147483648\t-2147483648\t\t\t\t\t\t\t\t\t\t\t\t\t-2147483648",
71 + "Wix5FirewallException:fex.BGtyMRGAhxb2hG.49JvWYz7fM0\tLocalScopeExample2\t*\t\t-2147483648\t\t0\t-2147483648\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tRule with local scope property\t1\t-2147483648\t-2147483648\t-2147483648\t\t\t\t\t[LOCALSCOPE_PROP]\t\t\t\t\t\t\t\t-2147483648",
72 + "Wix5FirewallException:fex0HTxATWjpC2PCoY6DB7f2D1WaKU\tLocalScopeExample1\t*\t\t-2147483648\t\t0\t-2147483648\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tSimple rule with local scope\t1\t-2147483648\t-2147483648\t-2147483648\t\t\t\t\tLocalSubnet\t\t\t\t\t\t\t\t-2147483648",
73 + "Wix5FirewallException:fex4FeP470wYcFpw.g7fbIKiLnZPzg\tExampleDNSScope\tdns\t356\t17\t\t0\t-2147483648\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tDNS scope firewall exception\t1\t-2147483648\t-2147483648\t-2147483648\t\t\t\t\t\t\t\t\t\t\t\t\t-2147483648",
74 + "Wix5FirewallException:fex4zTcT0Iwu3dUtHIHXD5qfymvpcM\tdefertouser\t\t\t-2147483648\tfw.exe\t8\t-2147483648\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tDefer to user edge traversal\t1\t-2147483648\t3\t-2147483648\t\t\t\t\t\t\t\t\t\t\t\t\t-2147483648",
75 + "Wix5FirewallException:fex8vMfBplrod4daEz3PqDTeX6olGE\tExampleDefaultGatewayScope\tDefaultGateway\t4432\t6\t\t0\t2\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tdefaultGateway scope firewall exception\t1\t-2147483648\t-2147483648\t-2147483648\t\t\t\t\t\t\t\t\t\t\t\t\t-2147483648",
76 + "Wix5FirewallException:fexAMmHzFDyQmubTOnKS1Cn0Y3q_Ug\tINetFwRule3 properties\t*\t\t-2147483648\t\t16\t-2147483648\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tINetFwRule3 passed via properties\t1\t-2147483648\t-2147483648\t-2147483648\t\t\t\t\t\t\t\t[PROP1]\t[PROP2]\t[PROP3]\t[PROP4]\t[PROP5]\t[PROP6]",
77 + "Wix5FirewallException:fexArlOkFR7CAwVZ2wk8yNdiREydu0\tRemotePortExample2\t\t\t6\tfw.exe\t0\t-2147483648\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tRule with remote port property\t1\t-2147483648\t-2147483648\t-2147483648\t\t\t\t\t\t[REMOTEPORT_PROP]\t\t\t\t\t\t\t-2147483648",
78 + "Wix5FirewallException:fexaUTe2tRRcSYrPUTn44DAZhE.40Q\tExamplePort\tLocalSubnet\t42\t6\t\t4\t-2147483648\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tA port-based firewall exception\t2\t-2147483648\t-2147483648\t-2147483648\t\t\t\t\t\t\t\t\t\t\t\t\t-2147483648",
79 + "Wix5FirewallException:fexD6w20c5HfNi4l1vHFj_eet4cC8I\tExampleWINSScope\twins\t6573\t6\t\t0\t1\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tWINS scope firewall exception\t1\t-2147483648\t-2147483648\t-2147483648\t\t\t\t\t\t\t\t\t\t\t\t\t-2147483648",
80 + "Wix5FirewallException:fexeD3yox6fMflfRy7sDwSN2CMCS2s\tExampleService\t\t12000\t6\t%windir%\\system32\\svchost.exe\t0\t-2147483648\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tA port-based service exception\t1\t-2147483648\t-2147483648\t-2147483648\t\t\t\t\tDHCP,WINS\t\tftpsrv\t\t\t\t\t\t-2147483648",
81 + "Wix5FirewallException:fexeok6aI2_AlclZggec4d8PBLFXLw\tinterface property\t\t54671\t6\t\t0\t-2147483648\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tInterfaces with property\t1\t-2147483648\t-2147483648\t-2147483648\t\t\t[INTERFACE_PROPERTY]\t\t\t\t\t\t\t\t\t\t-2147483648",
82 + "Wix5FirewallException:fexEPvcf4iexD1mVQdvxm7tD02nZEc\tICMPExample1\t\t\t2\t\t0\t-2147483648\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tSimple ICMP rule\t1\t-2147483648\t-2147483648\t-2147483648\t\t4:*,9:*,12:*\t\t\t\t\t\t\t\t\t\t\t-2147483648",
83 + "Wix5FirewallException:fexfzjTQsWwZkHQpObtl0XaUosfcRk\tGroupingExample1\t\t\t-2147483648\tfw.exe\t0\t-2147483648\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tSimple rule with grouping\t1\t-2147483648\t-2147483648\t-2147483648\t@yourresources.dll,-1005\t\t\t\t\t\t\t\t\t\t\t\t-2147483648",
84 + "Wix5FirewallException:fexHx2xbwZYzAi0oYp4YGWevJQs5eM\tRemotePortExample1\t*\t\t6\t\t0\t-2147483648\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tSimple rule with remote port\t1\t-2147483648\t-2147483648\t-2147483648\t\t\t\t\t\t34560\t\t\t\t\t\t\t-2147483648",
85 + "Wix5FirewallException:fexpWUzK53RVnaluW36gSmphPRY8VY\tExampleDHCPScope\tdhcp\t\t211\ttest.exe\t0\t4\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tDHCP scope firewall exception\t1\t-2147483648\t-2147483648\t-2147483648\t\t\t\t\t\t\t\t\t\t\t\t\t-2147483648",
86 + "Wix5FirewallException:fexuanTga5xaaFzr9JsAnUmpCNediw\tICMPExample2\t\t\t2\t\t0\t-2147483648\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tRule with ICMP property\t1\t-2147483648\t-2147483648\t-2147483648\t\t[ICMP_PROP]\t\t\t\t\t\t\t\t\t\t\t-2147483648",
87 + "Wix5FirewallException:fexv60s7u2Dmd1imH5vEFYKPgEWhG4\tinterface nested\t127.0.0.1\t54671\t6\t\t0\t-2147483648\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tInterfaces with nested elements\t1\t-2147483648\t-2147483648\t-2147483648\t\t\tWi-Fi|Local Area Connection\t\t\t\t\t\t\t\t\t\t-2147483648",
88 + "Wix5FirewallException:fexVr6uHcOCak5MHuTLwujjh_oKtbI\tGroupingExample2\t\t8732\t6\t\t0\t-2147483648\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tRule with grouping property\t1\t-2147483648\t-2147483648\t-2147483648\t[GROUPING_PROP]\t\t\t\t\t\t\t\t\t\t\t\t-2147483648",
89 + "Wix5FirewallException:fexwjf4OTFVE9SNiC4goVxBA6ENJBE\tINetFwRule3 values\t*\t\t-2147483648\t\t16\t-2147483648\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tSimple INetFwRule3 values\t1\t-2147483648\t-2147483648\t-2147483648\t\t\t\t\t\t\t\tS-1-15-2-1239072475-3687740317-1842961305-3395936705-4023953123-1525404051-2779347315\tO:LSD:(A;;CC;;;S-1-5-84-0-0-0-0-0)\tS-1-5-21-1898747406-2352535518-1247798438-1914\t127.0.0.1\tO:LSD:(A;;CC;;;S-1-5-84-0-0-0-0-0)\t3",
90 + "Wix5FirewallException:ServiceInstall.nested\tExampleNestedService\tLocalSubnet\t3546-7890\t6\t\t1\t-2147483648\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tA port-based firewall exception for a windows service\t1\t-2147483648\t-2147483648\t-2147483648\t\t\t\tLan,Wireless\t\t\tsvc1\t\t\t\t\t\t-2147483648",
91 + }, results);
92 + }
93 +
94 + [Fact]
95 + public void CanBuildWithProperties()
96 + {
97 + var folder = TestData.Get(@"TestData\UsingProperties");
98 + var build = new Builder(folder, typeof(FirewallExtensionFactory), new[] { folder });
99 +
100 + var results = build.BuildAndQuery(Build, "Wix5FirewallException", "CustomAction");
101 + WixAssert.CompareLineByLine(new[]
102 + {
103 + "CustomAction:Wix5ExecFirewallExceptionsInstall_X86\t3073\tWix5FWCA_X86\tExecFirewallExceptions\t",
104 + "CustomAction:Wix5ExecFirewallExceptionsUninstall_X86\t3073\tWix5FWCA_X86\tExecFirewallExceptions\t",
105 + "CustomAction:Wix5RollbackFirewallExceptionsInstall_X86\t3329\tWix5FWCA_X86\tExecFirewallExceptions\t",
106 + "CustomAction:Wix5RollbackFirewallExceptionsUninstall_X86\t3329\tWix5FWCA_X86\tExecFirewallExceptions\t",
107 + "CustomAction:Wix5SchedFirewallExceptionsInstall_X86\t1\tWix5FWCA_X86\tSchedFirewallExceptionsInstall\t",
108 + "CustomAction:Wix5SchedFirewallExceptionsUninstall_X86\t1\tWix5FWCA_X86\tSchedFirewallExceptionsUninstall\t",
109 + "Wix5FirewallException:fexRrE4bS.DwUJQMvzX0ALEsx7jrZs\tSingle Nested properties\t[REMOTEADDRESS]\t\t-2147483648\t\t0\t-2147483648\tFirewallComponent\t\t1\t-2147483648\t-2147483648\t-2147483648\t\t\t[INTERFACE]\t[INTERFACETYPE]\t[LOCALADDRESS]\t\t\t\t\t\t\t\t-2147483648",
110 + "Wix5FirewallException:fexvEy1GfdOjHlKcvsguyqK6mvYKyk\t[NAME]\t[REMOTESCOPE]\t[LOCALPORT]\t[PROTOCOL]\t[PROGRAM]\t16\t[PROFILE]\tFirewallComponent\t[DESCRIPTION]\t1\t[ACTION]\t[EDGETRAVERSAL]\t[ENABLED]\t[GROUPING]\t[ICMPTYPES]\t[INTERFACE]\t[INTERFACETYPE]\t[LOCALSCOPE]\t[REMOTEPORT]\t[SERVICE]\t[PACKAGEID]\t[LOCALUSERS]\t[LOCALOWNER]\t[REMOTEMACHINES]\t[REMOTEUSERS]\t[SECUREFLAGS]",
111 + "Wix5FirewallException:fexWywW3VGiEuG23FOv1YM6h7R6F5Q\tMultiple Nested properties\t[REMOTEADDRESS1],[REMOTEADDRESS2]\t\t-2147483648\t\t0\t-2147483648\tFirewallComponent\t\t1\t-2147483648\t-2147483648\t-2147483648\t\t\t[INTERFACE1]|[INTERFACE2]\t[INTERFACETYPE1],[INTERFACETYPE2]\t[LOCALADDRESS1],[LOCALADDRESS2]\t\t\t\t\t\t\t\t-2147483648",
112 + }, results);
113 + }
114 +
115 + [Fact]
116 + public void CanBuildWithPropertiesUsingFirewallARM64()
117 + {
118 + var folder = TestData.Get(@"TestData\UsingProperties");
119 + var build = new Builder(folder, typeof(FirewallExtensionFactory), new[] { folder });
120 +
121 + var results = build.BuildAndQuery(BuildARM64, "Wix5FirewallException", "CustomAction");
122 + WixAssert.CompareLineByLine(new[]
123 + {
124 + "CustomAction:Wix5ExecFirewallExceptionsInstall_A64\t3073\tWix5FWCA_A64\tExecFirewallExceptions\t",
125 + "CustomAction:Wix5ExecFirewallExceptionsUninstall_A64\t3073\tWix5FWCA_A64\tExecFirewallExceptions\t",
126 + "CustomAction:Wix5RollbackFirewallExceptionsInstall_A64\t3329\tWix5FWCA_A64\tExecFirewallExceptions\t",
127 + "CustomAction:Wix5RollbackFirewallExceptionsUninstall_A64\t3329\tWix5FWCA_A64\tExecFirewallExceptions\t",
128 + "CustomAction:Wix5SchedFirewallExceptionsInstall_A64\t1\tWix5FWCA_A64\tSchedFirewallExceptionsInstall\t",
129 + "CustomAction:Wix5SchedFirewallExceptionsUninstall_A64\t1\tWix5FWCA_A64\tSchedFirewallExceptionsUninstall\t",
130 + "Wix5FirewallException:fexRrE4bS.DwUJQMvzX0ALEsx7jrZs\tSingle Nested properties\t[REMOTEADDRESS]\t\t-2147483648\t\t0\t-2147483648\tFirewallComponent\t\t1\t-2147483648\t-2147483648\t-2147483648\t\t\t[INTERFACE]\t[INTERFACETYPE]\t[LOCALADDRESS]\t\t\t\t\t\t\t\t-2147483648",
131 + "Wix5FirewallException:fexvEy1GfdOjHlKcvsguyqK6mvYKyk\t[NAME]\t[REMOTESCOPE]\t[LOCALPORT]\t[PROTOCOL]\t[PROGRAM]\t16\t[PROFILE]\tFirewallComponent\t[DESCRIPTION]\t1\t[ACTION]\t[EDGETRAVERSAL]\t[ENABLED]\t[GROUPING]\t[ICMPTYPES]\t[INTERFACE]\t[INTERFACETYPE]\t[LOCALSCOPE]\t[REMOTEPORT]\t[SERVICE]\t[PACKAGEID]\t[LOCALUSERS]\t[LOCALOWNER]\t[REMOTEMACHINES]\t[REMOTEUSERS]\t[SECUREFLAGS]",
132 + "Wix5FirewallException:fexWywW3VGiEuG23FOv1YM6h7R6F5Q\tMultiple Nested properties\t[REMOTEADDRESS1],[REMOTEADDRESS2]\t\t-2147483648\t\t0\t-2147483648\tFirewallComponent\t\t1\t-2147483648\t-2147483648\t-2147483648\t\t\t[INTERFACE1]|[INTERFACE2]\t[INTERFACETYPE1],[INTERFACETYPE2]\t[LOCALADDRESS1],[LOCALADDRESS2]\t\t\t\t\t\t\t\t-2147483648",
133 }, results);
134 }
135
@@ -83,6 +156,59 @@ namespace WixToolsetTest.Firewall
156 "FirewallException",
157 "FirewallException",
158 "FirewallException",
159 + "FirewallException",
160 + "FirewallException",
161 + "LocalAddress",
162 + "LocalAddress",
163 + "FirewallException",
164 + "RemoteAddress",
165 + "Interface",
166 + "Interface",
167 + "FirewallException",
168 + "FirewallException",
169 + "InterfaceType",
170 + "InterfaceType",
171 + "FirewallException",
172 + "FirewallException",
173 + "FirewallException",
174 + "FirewallException",
175 + "FirewallException",
176 + "FirewallException",
177 + "FirewallException",
178 + "FirewallException",
179 + "FirewallException",
180 + "FirewallException",
181 + }, actual.Select(a => a.Name).ToArray());
182 + }
183 +
184 + [Fact]
185 + public void CanRoundtripFirewallExceptionsWithProperties()
186 + {
187 + var folder = TestData.Get(@"TestData", "UsingProperties");
188 + var build = new Builder(folder, typeof(FirewallExtensionFactory), new[] { folder });
189 + var output = Path.Combine(folder, "FirewallPropertiesDecompile.xml");
190 +
191 + build.BuildAndDecompileAndBuild(Build, Decompile, output);
192 +
193 + var doc = XDocument.Load(output);
194 + var actual = doc.Descendants()
195 + .Where(e => e.Name.Namespace == "http://wixtoolset.org/schemas/v4/wxs/firewall")
196 + .Select(fe => new { Name = fe.Name.LocalName, Attributes = fe.Attributes().Select(a => $"{a.Name.LocalName}={a.Value}").ToArray() })
197 + .ToArray();
198 +
199 + WixAssert.CompareLineByLine(new[]
200 + {
201 + "FirewallException",
202 + "FirewallException",
203 + "FirewallException",
204 + "RemoteAddress",
205 + "RemoteAddress",
206 + "Interface",
207 + "Interface",
208 + "InterfaceType",
209 + "InterfaceType",
210 + "LocalAddress",
211 + "LocalAddress",
212 }, actual.Select(a => a.Name).ToArray());
213 }
214
@@ -98,9 +224,8 @@ namespace WixToolsetTest.Firewall
224 "Port=42",
225 "Protocol=tcp",
226 "Program=[#filNdJBJmq3UCUIwmXS8x21aAsvqzk]",
101 - "Profile=all",
227 + "OnUpdate=DoNothing",
228 "Description=An app-based firewall exception",
103 - "Outbound=no",
229 "xmlns=http://wixtoolset.org/schemas/v4/wxs/firewall",
230 }, actual.Attributes);
231 }
@@ -111,12 +236,12 @@ namespace WixToolsetTest.Firewall
236 var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "ExamplePort");
237 WixAssert.CompareLineByLine(new[]
238 {
114 - "Id=fex70IVsYNnbwiHQrEepmdTPKH8XYs",
239 + "Id=fexaUTe2tRRcSYrPUTn44DAZhE.40Q",
240 "Name=ExamplePort",
241 "Scope=localSubnet",
242 "Port=42",
243 "Protocol=tcp",
119 - "Profile=all",
244 + "OnUpdate=EnableOnly",
245 "Description=A port-based firewall exception",
246 "Outbound=yes",
247 "xmlns=http://wixtoolset.org/schemas/v4/wxs/firewall",
@@ -129,14 +254,12 @@ namespace WixToolsetTest.Firewall
254 var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "ExampleDNSScope");
255 WixAssert.CompareLineByLine(new[]
256 {
132 - "Id=fexxY71H2ZBkPalv7uid1Yy4qaA_lA",
257 + "Id=fex4FeP470wYcFpw.g7fbIKiLnZPzg",
258 "Name=ExampleDNSScope",
259 "Scope=DNS",
260 "Port=356",
261 "Protocol=udp",
137 - "Profile=all",
262 "Description=DNS scope firewall exception",
139 - "Outbound=no",
263 "xmlns=http://wixtoolset.org/schemas/v4/wxs/firewall",
264 }, actual.Attributes);
265 }
@@ -147,14 +270,13 @@ namespace WixToolsetTest.Firewall
270 var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "ExampleDHCPScope");
271 WixAssert.CompareLineByLine(new[]
272 {
150 - "Id=fex6bkfWwpiRGI.wVFx0T7W4LXIHxU",
273 + "Id=fexpWUzK53RVnaluW36gSmphPRY8VY",
274 "Name=ExampleDHCPScope",
275 "Scope=DHCP",
276 "Protocol=211",
277 "Program=test.exe",
278 "Profile=public",
279 "Description=DHCP scope firewall exception",
157 - "Outbound=no",
280 "xmlns=http://wixtoolset.org/schemas/v4/wxs/firewall"
281 }, actual.Attributes);
282 }
@@ -165,14 +287,13 @@ namespace WixToolsetTest.Firewall
287 var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "ExampleWINSScope");
288 WixAssert.CompareLineByLine(new[]
289 {
168 - "Id=fexXxaXCXXFh.UxO_BjmZxi1B1du_Q",
290 + "Id=fexD6w20c5HfNi4l1vHFj_eet4cC8I",
291 "Name=ExampleWINSScope",
292 "Scope=WINS",
293 "Port=6573",
294 "Protocol=tcp",
295 "Profile=domain",
296 "Description=WINS scope firewall exception",
175 - "Outbound=no",
297 "xmlns=http://wixtoolset.org/schemas/v4/wxs/firewall",
298 }, actual.Attributes);
299 }
@@ -183,18 +304,322 @@ namespace WixToolsetTest.Firewall
304 var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "ExampleDefaultGatewayScope");
305 WixAssert.CompareLineByLine(new[]
306 {
186 - "Id=fex_ZpDsnKyHlYiA24JHzvFxm3uLZ8",
307 + "Id=fex8vMfBplrod4daEz3PqDTeX6olGE",
308 "Name=ExampleDefaultGatewayScope",
309 "Scope=defaultGateway",
310 "Port=4432",
311 "Protocol=tcp",
312 "Profile=private",
313 "Description=defaultGateway scope firewall exception",
193 - "Outbound=no",
314 "xmlns=http://wixtoolset.org/schemas/v4/wxs/firewall",
315 }, actual.Attributes);
316 }
317
318 + [Fact]
319 + public void RoundtripAttributesAreCorrectForINetFwRule3Values()
320 + {
321 + var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "INetFwRule3 values");
322 + WixAssert.CompareLineByLine(new[]
323 + {
324 + "Id=fexwjf4OTFVE9SNiC4goVxBA6ENJBE",
325 + "Name=INetFwRule3 values",
326 + "Scope=any",
327 + "Description=Simple INetFwRule3 values",
328 + "LocalAppPackageId=S-1-15-2-1239072475-3687740317-1842961305-3395936705-4023953123-1525404051-2779347315",
329 + "LocalUserAuthorizedList=O:LSD:(A;;CC;;;S-1-5-84-0-0-0-0-0)",
330 + "LocalUserOwner=S-1-5-21-1898747406-2352535518-1247798438-1914",
331 + "RemoteMachineAuthorizedList=127.0.0.1",
332 + "RemoteUserAuthorizedList=O:LSD:(A;;CC;;;S-1-5-84-0-0-0-0-0)",
333 + "IPSecSecureFlags=NegotiateEncryption",
334 + "xmlns=http://wixtoolset.org/schemas/v4/wxs/firewall",
335 + }, actual.Attributes);
336 + }
337 +
338 + [Fact]
339 + public void RoundtripAttributesAreCorrectForINetFwRule3Properties()
340 + {
341 + var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "INetFwRule3 properties");
342 + WixAssert.CompareLineByLine(new[]
343 + {
344 + "Id=fexAMmHzFDyQmubTOnKS1Cn0Y3q_Ug",
345 + "Name=INetFwRule3 properties",
346 + "Scope=any",
347 + "Description=INetFwRule3 passed via properties",
348 + "LocalAppPackageId=[PROP1]",
349 + "LocalUserAuthorizedList=[PROP2]",
350 + "LocalUserOwner=[PROP3]",
351 + "RemoteMachineAuthorizedList=[PROP4]",
352 + "RemoteUserAuthorizedList=[PROP5]",
353 + "IPSecSecureFlags=[PROP6]",
354 + "xmlns=http://wixtoolset.org/schemas/v4/wxs/firewall",
355 + }, actual.Attributes);
356 + }
357 +
358 + [Fact]
359 + public void RoundtripAttributesAreCorrectForGroupingValue()
360 + {
361 + var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "GroupingExample1");
362 + WixAssert.CompareLineByLine(new[]
363 + {
364 + "Id=fexfzjTQsWwZkHQpObtl0XaUosfcRk",
365 + "Name=GroupingExample1",
366 + "Program=fw.exe",
367 + "Description=Simple rule with grouping",
368 + "Grouping=@yourresources.dll,-1005",
369 + "xmlns=http://wixtoolset.org/schemas/v4/wxs/firewall",
370 + }, actual.Attributes);
371 + }
372 +
373 + [Fact]
374 + public void RoundtripAttributesAreCorrectForGroupingProperty()
375 + {
376 + var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "GroupingExample2");
377 + WixAssert.CompareLineByLine(new[]
378 + {
379 + "Id=fexVr6uHcOCak5MHuTLwujjh_oKtbI",
380 + "Name=GroupingExample2",
381 + "Port=8732",
382 + "Protocol=tcp",
383 + "Description=Rule with grouping property",
384 + "Grouping=[GROUPING_PROP]",
385 + "xmlns=http://wixtoolset.org/schemas/v4/wxs/firewall",
386 + }, actual.Attributes);
387 + }
388 +
389 + [Fact]
390 + public void RoundtripAttributesAreCorrectForIcmpValue()
391 + {
392 + var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "ICMPExample1");
393 + WixAssert.CompareLineByLine(new[]
394 + {
395 + "Id=fexEPvcf4iexD1mVQdvxm7tD02nZEc",
396 + "Name=ICMPExample1",
397 + "Protocol=2",
398 + "Description=Simple ICMP rule",
399 + "IcmpTypesAndCodes=4:*,9:*,12:*",
400 + "xmlns=http://wixtoolset.org/schemas/v4/wxs/firewall",
401 + }, actual.Attributes);
402 + }
403 +
404 + [Fact]
405 + public void RoundtripAttributesAreCorrectForIcmpProperty()
406 + {
407 + var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "ICMPExample2");
408 + WixAssert.CompareLineByLine(new[]
409 + {
410 + "Id=fexuanTga5xaaFzr9JsAnUmpCNediw",
411 + "Name=ICMPExample2",
412 + "Protocol=2",
413 + "Description=Rule with ICMP property",
414 + "IcmpTypesAndCodes=[ICMP_PROP]",
415 + "xmlns=http://wixtoolset.org/schemas/v4/wxs/firewall",
416 + }, actual.Attributes);
417 + }
418 +
419 + [Fact]
420 + public void RoundtripAttributesAreCorrectForLocalScopeValue()
421 + {
422 + var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "LocalScopeExample1");
423 + WixAssert.CompareLineByLine(new[]
424 + {
425 + "Id=fex0HTxATWjpC2PCoY6DB7f2D1WaKU",
426 + "Name=LocalScopeExample1",
427 + "Scope=any",
428 + "Description=Simple rule with local scope",
429 + "LocalScope=localSubnet",
430 + "xmlns=http://wixtoolset.org/schemas/v4/wxs/firewall",
431 + }, actual.Attributes);
432 + }
433 +
434 + [Fact]
435 + public void RoundtripAttributesAreCorrectForLocalScopeProperty()
436 + {
437 + var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "LocalScopeExample2");
438 + WixAssert.CompareLineByLine(new[]
439 + {
440 + "Id=fex.BGtyMRGAhxb2hG.49JvWYz7fM0",
441 + "Name=LocalScopeExample2",
442 + "Scope=any",
443 + "Description=Rule with local scope property",
444 + "LocalScope=[LOCALSCOPE_PROP]",
445 + "xmlns=http://wixtoolset.org/schemas/v4/wxs/firewall",
446 + }, actual.Attributes);
447 + }
448 +
449 + [Fact]
450 + public void RoundtripAttributesAreCorrectForRemotePorts()
451 + {
452 + var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "RemotePortExample1");
453 + WixAssert.CompareLineByLine(new[]
454 + {
455 + "Id=fexHx2xbwZYzAi0oYp4YGWevJQs5eM",
456 + "Name=RemotePortExample1",
457 + "Scope=any",
458 + "Protocol=tcp",
459 + "Description=Simple rule with remote port",
460 + "RemotePort=34560",
461 + "xmlns=http://wixtoolset.org/schemas/v4/wxs/firewall",
462 + }, actual.Attributes);
463 + }
464 +
465 + [Fact]
466 + public void RoundtripAttributesAreCorrectForRemotePortsProperty()
467 + {
468 + var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "RemotePortExample2");
469 + WixAssert.CompareLineByLine(new[]
470 + {
471 + "Id=fexArlOkFR7CAwVZ2wk8yNdiREydu0",
472 + "Name=RemotePortExample2",
473 + "Protocol=tcp",
474 + "Program=fw.exe",
475 + "Description=Rule with remote port property",
476 + "RemotePort=[REMOTEPORT_PROP]",
477 + "xmlns=http://wixtoolset.org/schemas/v4/wxs/firewall",
478 + }, actual.Attributes);
479 + }
480 +
481 + [Fact]
482 + public void RoundtripAttributesAreCorrectWhenPropertiesAreUsed()
483 + {
484 + var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "[NAME]", "UsingProperties");
485 + WixAssert.CompareLineByLine(new[]
486 + {
487 + "Id=fexvEy1GfdOjHlKcvsguyqK6mvYKyk",
488 + "Name=[NAME]",
489 + "Scope=[REMOTESCOPE]",
490 + "Port=[LOCALPORT]",
491 + "Protocol=[PROTOCOL]",
492 + "Program=[PROGRAM]",
493 + "Profile=[PROFILE]",
494 + "Description=[DESCRIPTION]",
495 + "Action=[ACTION]",
496 + "EdgeTraversal=[EDGETRAVERSAL]",
497 + "Enabled=[ENABLED]",
498 + "Grouping=[GROUPING]",
499 + "IcmpTypesAndCodes=[ICMPTYPES]",
500 + "Interface=[INTERFACE]",
501 + "InterfaceType=[INTERFACETYPE]",
502 + "LocalScope=[LOCALSCOPE]",
503 + "RemotePort=[REMOTEPORT]",
504 + "Service=[SERVICE]",
505 + "LocalAppPackageId=[PACKAGEID]",
506 + "LocalUserAuthorizedList=[LOCALUSERS]",
507 + "LocalUserOwner=[LOCALOWNER]",
508 + "RemoteMachineAuthorizedList=[REMOTEMACHINES]",
509 + "RemoteUserAuthorizedList=[REMOTEUSERS]",
510 + "IPSecSecureFlags=[SECUREFLAGS]",
511 + "xmlns=http://wixtoolset.org/schemas/v4/wxs/firewall"
512 + }, actual.Attributes);
513 +
514 + var folder = TestData.Get(@"TestData", "UsingProperties");
515 + var build = new Builder(folder, typeof(FirewallExtensionFactory), new[] { folder });
516 + var output = Path.Combine(folder, $"FirewallNothingNested.xml");
517 +
518 + build.BuildAndDecompileAndBuild(Build, Decompile, output);
519 +
520 + var doc = XDocument.Load(output);
521 + var related = doc.Descendants()
522 + .Where(e =>
523 + {
524 + return e.Name.Namespace == "http://wixtoolset.org/schemas/v4/wxs/firewall" &&
525 + e.Parent.Attributes().Any(a => a.Name.LocalName == "Name" && a.Value == "[NAME]");
526 + });
527 +
528 + var nested = related.Select(e => e.Attributes().Single(a => a.Name.LocalName == "Name").Value);
529 + Assert.False(nested.Any());
530 + }
531 +
532 + [Fact]
533 + public void RoundtripAttributesAreCorrectWhenNestedPropertiesAreUsed()
534 + {
535 + var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "Single Nested properties", "UsingProperties");
536 + WixAssert.CompareLineByLine(new[]
537 + {
538 + "Id=fexRrE4bS.DwUJQMvzX0ALEsx7jrZs",
539 + "Name=Single Nested properties",
540 + "Scope=[REMOTEADDRESS]",
541 + "Interface=[INTERFACE]",
542 + "InterfaceType=[INTERFACETYPE]",
543 + "LocalScope=[LOCALADDRESS]",
544 + "xmlns=http://wixtoolset.org/schemas/v4/wxs/firewall"
545 + }, actual.Attributes);
546 +
547 + var folder = TestData.Get(@"TestData", "UsingProperties");
548 + var build = new Builder(folder, typeof(FirewallExtensionFactory), new[] { folder });
549 + var output = Path.Combine(folder, $"FirewallSingleNested.xml");
550 +
551 + build.BuildAndDecompileAndBuild(Build, Decompile, output);
552 +
553 + var doc = XDocument.Load(output);
554 + var related = doc.Descendants()
555 + .Where(e =>
556 + {
557 + return e.Name.Namespace == "http://wixtoolset.org/schemas/v4/wxs/firewall" &&
558 + e.Parent.Attributes().Any(a => a.Name.LocalName == "Name" && a.Value == "Single Nested properties");
559 + });
560 +
561 + var nested = related.Select(e => e.Attributes().Single(a => a.Name.LocalName == "Name").Value);
562 + Assert.False(nested.Any());
563 + }
564 +
565 + [Fact]
566 + public void RoundtripAttributesAreCorrectWhenMultipleNestedPropertiesAreUsed()
567 + {
568 + var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "Multiple Nested properties", "UsingProperties");
569 + WixAssert.CompareLineByLine(new[]
570 + {
571 + "Id=fexWywW3VGiEuG23FOv1YM6h7R6F5Q",
572 + "Name=Multiple Nested properties",
573 + "xmlns=http://wixtoolset.org/schemas/v4/wxs/firewall"
574 + }, actual.Attributes);
575 +
576 + var folder = TestData.Get(@"TestData", "UsingProperties");
577 + var build = new Builder(folder, typeof(FirewallExtensionFactory), new[] { folder });
578 + var output = Path.Combine(folder, $"FirewallMultipleNested.xml");
579 +
580 + build.BuildAndDecompileAndBuild(Build, Decompile, output);
581 +
582 + var doc = XDocument.Load(output);
583 + var related = doc.Descendants()
584 + .Where(e =>
585 + {
586 + return e.Name.Namespace == "http://wixtoolset.org/schemas/v4/wxs/firewall" &&
587 + e.Parent.Attributes().Any(a => a.Name.LocalName == "Name" && a.Value == "Multiple Nested properties");
588 + });
589 +
590 + var interfaces = related.Where(e => e.Name.LocalName == "Interface")
591 + .Select(e => e.Attributes().Single(a => a.Name.LocalName == "Name").Value);
592 + WixAssert.CompareLineByLine(new[]
593 + {
594 + "[INTERFACE1]",
595 + "[INTERFACE2]",
596 + }, interfaces.ToArray());
597 +
598 + var interfaceTypes = related.Where(e => e.Name.LocalName == "InterfaceType")
599 + .Select(e => e.Attributes().Single(a => a.Name.LocalName == "Value").Value);
600 + WixAssert.CompareLineByLine(new[]
601 + {
602 + "[INTERFACETYPE1]",
603 + "[INTERFACETYPE2]",
604 + }, interfaceTypes.ToArray());
605 +
606 + var remotes = related.Where(e => e.Name.LocalName == "RemoteAddress")
607 + .Select(e => e.Attributes().Single(a => a.Name.LocalName == "Value").Value);
608 + WixAssert.CompareLineByLine(new[]
609 + {
610 + "[REMOTEADDRESS1]",
611 + "[REMOTEADDRESS2]",
612 + }, remotes.ToArray());
613 +
614 + var locals = related.Where(e => e.Name.LocalName == "LocalAddress")
615 + .Select(e => e.Attributes().Single(a => a.Name.LocalName == "Value").Value);
616 + WixAssert.CompareLineByLine(new[]
617 + {
618 + "[LOCALADDRESS1]",
619 + "[LOCALADDRESS2]",
620 + }, locals.ToArray());
621 + }
622 +
623 private static void Build(string[] args)
624 {
625 var result = WixRunner.Execute(args);
@@ -216,15 +641,16 @@ namespace WixToolsetTest.Firewall
641 var result = WixRunner.Execute(args);
642 result.AssertSuccess();
643 }
644 +
645 class AttributeVerifier
646 {
647 public string Name { get; set; }
648 public string[] Attributes { get; set; }
649 }
650
225 - private static AttributeVerifier BuildAndDecompileAndBuild(string nameSpace, string ruleName)
651 + private static AttributeVerifier BuildAndDecompileAndBuild(string nameSpace, string ruleName, string path = "UsingFirewall")
652 {
227 - var folder = TestData.Get(@"TestData", "UsingFirewall");
653 + var folder = TestData.Get(@"TestData", path);
654 var build = new Builder(folder, typeof(FirewallExtensionFactory), new[] { folder });
655 var output = Path.Combine(folder, $"Firewall{ruleName}.xml");
656
@@ -232,7 +658,10 @@ namespace WixToolsetTest.Firewall
658
659 var doc = XDocument.Load(output);
660 var actual = doc.Descendants()
235 - .Where(e => e.Name.Namespace == nameSpace)
661 + .Where(e =>
662 + {
663 + return e.Name.Namespace == nameSpace && e.Name.LocalName == "FirewallException";
664 + })
665 .Select(fe => new AttributeVerifier
666 {
667 Name = fe.Attributes().Single(a => a.Name.LocalName == "Name").Value,
src/ext/Firewall/test/WixToolsetTest.Firewall/TestData/UsingFirewall/PackageComponents.wxs
+37 -2
@@ -6,16 +6,51 @@
6 <Component>
7 <File Name="fw.exe" Source="example.txt">
8 <Shortcut Id="FwShortcut" Directory="INSTALLFOLDER" Name="Firewall" />
9 - <fw:FirewallException Id="ExampleFirewall" Description="An app-based firewall exception" Name="ExampleApp" Port="42">
9 + <fw:FirewallException Id="ExampleFirewall" Description="An app-based firewall exception" Name="ExampleApp" Port="42" OnUpdate="DoNothing" >
10 <fw:RemoteAddress Value="*" />
11 </fw:FirewallException>
12 </File>
13
14 - <fw:FirewallException Description="A port-based firewall exception" Name="ExamplePort" Port="42" Outbound="yes" Scope="localSubnet" />
14 + <fw:FirewallException Description="A port-based firewall exception" Name="ExamplePort" Port="42" Outbound="yes" Scope="localSubnet" OnUpdate="EnableOnly" />
15 <fw:FirewallException Description="DNS scope firewall exception" Name="ExampleDNSScope" Port="356" Protocol="udp" Scope="DNS" />
16 <fw:FirewallException Description="DHCP scope firewall exception" Name="ExampleDHCPScope" Program="test.exe" Protocol="211" Scope="DHCP" Profile="public" />
17 <fw:FirewallException Description="WINS scope firewall exception" Name="ExampleWINSScope" Port="6573" Scope="WINS" Profile="domain"/>
18 <fw:FirewallException Description="defaultGateway scope firewall exception" Name="ExampleDefaultGatewayScope" Port="4432" Scope="defaultGateway" Profile="private" />
19 +
20 + <fw:FirewallException Description="Defer to user edge traversal" Name="defertouser" Program="fw.exe" EdgeTraversal="DeferToUser" />
21 + <fw:FirewallException Description="A port-based service exception" Name="ExampleService" Port="12000" Service="ftpsrv" Program="%windir%\system32\svchost.exe" >
22 + <fw:LocalAddress Value="DHCP"/>
23 + <fw:LocalAddress Value="WINS"/>
24 + </fw:FirewallException>
25 +
26 + <fw:FirewallException Description="Interfaces with nested elements" Name="interface nested" Port="54671" >
27 + <fw:RemoteAddress Value="127.0.0.1"/>
28 + <fw:Interface Name="Wi-Fi" />
29 + <fw:Interface Name="Local Area Connection" />
30 + </fw:FirewallException>
31 + <fw:FirewallException Description="Interfaces with property" Name="interface property" Port="54671" Interface="[INTERFACE_PROPERTY]" />
32 +
33 + <ServiceInstall Name="svc1" Type="ownProcess" Start="disabled" ErrorControl="ignore" >
34 + <fw:FirewallException Id="ServiceInstall.nested" IgnoreFailure="true" Description="A port-based firewall exception for a windows service" Name="ExampleNestedService" Port="3546-7890" Scope="localSubnet" >
35 + <fw:InterfaceType Value="Lan" />
36 + <fw:InterfaceType Value="Wireless" />
37 + </fw:FirewallException>
38 + </ServiceInstall>
39 +
40 + <fw:FirewallException Description="Simple INetFwRule3 values" Name="INetFwRule3 values" Scope="any" LocalAppPackageId="S-1-15-2-1239072475-3687740317-1842961305-3395936705-4023953123-1525404051-2779347315" LocalUserAuthorizedList="O:LSD:(A;;CC;;;S-1-5-84-0-0-0-0-0)" LocalUserOwner="S-1-5-21-1898747406-2352535518-1247798438-1914" RemoteMachineAuthorizedList="127.0.0.1" RemoteUserAuthorizedList="O:LSD:(A;;CC;;;S-1-5-84-0-0-0-0-0)" IPSecSecureFlags="NegotiateEncryption" />
41 + <fw:FirewallException Description="INetFwRule3 passed via properties" Name="INetFwRule3 properties" Scope="any" LocalAppPackageId="[PROP1]" LocalUserAuthorizedList="[PROP2]" LocalUserOwner="[PROP3]" RemoteMachineAuthorizedList="[PROP4]" RemoteUserAuthorizedList="[PROP5]" IPSecSecureFlags="[PROP6]" />
42 +
43 + <fw:FirewallException Description="Simple rule with grouping" Name="GroupingExample1" Program="fw.exe" Grouping="@yourresources.dll,-1005" />
44 + <fw:FirewallException Description="Rule with grouping property" Name="GroupingExample2" Port="8732" Grouping="[GROUPING_PROP]" />
45 +
46 + <fw:FirewallException Description="Simple ICMP rule" Name="ICMPExample1" Protocol="2" IcmpTypesAndCodes="4:*,9:*,12:*" />
47 + <fw:FirewallException Description="Rule with ICMP property" Name="ICMPExample2" Protocol="2" IcmpTypesAndCodes="[ICMP_PROP]" />
48 +
49 + <fw:FirewallException Description="Simple rule with local scope" Name="LocalScopeExample1" Scope="any" LocalScope="localSubnet" />
50 + <fw:FirewallException Description="Rule with local scope property" Name="LocalScopeExample2" Scope="any" LocalScope="[LOCALSCOPE_PROP]" />
51 +
52 + <fw:FirewallException Description="Simple rule with remote port" Name="RemotePortExample1" Scope="any" RemotePort="34560" />
53 + <fw:FirewallException Description="Rule with remote port property" Name="RemotePortExample2" Program="fw.exe" RemotePort="[REMOTEPORT_PROP]" />
54 </Component>
55 </ComponentGroup>
56 </Fragment>
src/ext/Firewall/test/WixToolsetTest.Firewall/TestData/UsingProperties/Package.en-us.wxl new
+9
@@ -0,0 +1,9 @@
1 +<!--
2 +This file contains the declaration of all the localizable strings.
3 +-->
4 +<WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="en-US">
5 +
6 + <String Id="DowngradeError" Value="A newer version of [ProductName] is already installed." />
7 + <String Id="FeatureTitle" Value="MsiPackage" />
8 +
9 +</WixLocalization>
src/ext/Firewall/test/WixToolsetTest.Firewall/TestData/UsingProperties/Package.wxs new
+15
@@ -0,0 +1,15 @@
1 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
2 + <Package Name="MsiPackage" Language="1033" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="BB4E61B3-EBE5-4DE7-B3E0-8699B5901D2E">
3 + <MajorUpgrade DowngradeErrorMessage="!(loc.DowngradeError)" />
4 +
5 + <Feature Id="ProductFeature" Title="!(loc.FeatureTitle)">
6 + <ComponentGroupRef Id="ProductComponents" />
7 + </Feature>
8 + </Package>
9 +
10 + <Fragment>
11 + <StandardDirectory Id="ProgramFilesFolder">
12 + <Directory Id="INSTALLFOLDER" Name="MsiPackage" />
13 + </StandardDirectory>
14 + </Fragment>
15 +</Wix>
src/ext/Firewall/test/WixToolsetTest.Firewall/TestData/UsingProperties/PackageComponents.wxs new
+53
@@ -0,0 +1,53 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"
3 + xmlns:fw="http://wixtoolset.org/schemas/v4/wxs/firewall">
4 + <Fragment>
5 + <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
6 + <Component Id="FirewallComponent" Guid="28DF3387-F30E-4DBE-90E2-D2C760CB4DD9">
7 + <fw:FirewallException
8 + Name="[NAME]"
9 + Port="[LOCALPORT]"
10 + Protocol="[PROTOCOL]"
11 + Program="[PROGRAM]"
12 + Profile="[PROFILE]"
13 + Description="[DESCRIPTION]"
14 + Scope="[REMOTESCOPE]"
15 + Action="[ACTION]"
16 + EdgeTraversal="[EDGETRAVERSAL]"
17 + Enabled="[ENABLED]"
18 + Grouping="[GROUPING]"
19 + IcmpTypesAndCodes="[ICMPTYPES]"
20 + Interface="[INTERFACE]"
21 + InterfaceType="[INTERFACETYPE]"
22 + LocalScope="[LOCALSCOPE]"
23 + RemotePort="[REMOTEPORT]"
24 + Service="[SERVICE]"
25 + LocalAppPackageId="[PACKAGEID]"
26 + LocalUserAuthorizedList="[LOCALUSERS]"
27 + LocalUserOwner="[LOCALOWNER]"
28 + RemoteMachineAuthorizedList="[REMOTEMACHINES]"
29 + RemoteUserAuthorizedList="[REMOTEUSERS]"
30 + IPSecSecureFlags="[SECUREFLAGS]"
31 + />
32 +
33 + <fw:FirewallException Name="Single Nested properties" >
34 + <fw:RemoteAddress Value="[REMOTEADDRESS]" />
35 + <fw:LocalAddress Value="[LOCALADDRESS]" />
36 + <fw:InterfaceType Value="[INTERFACETYPE]" />
37 + <fw:Interface Name="[INTERFACE]" />
38 + </fw:FirewallException>
39 +
40 + <fw:FirewallException Name="Multiple Nested properties" >
41 + <fw:RemoteAddress Value="[REMOTEADDRESS1]" />
42 + <fw:RemoteAddress Value="[REMOTEADDRESS2]" />
43 + <fw:LocalAddress Value="[LOCALADDRESS1]" />
44 + <fw:LocalAddress Value="[LOCALADDRESS2]" />
45 + <fw:InterfaceType Value="[INTERFACETYPE1]" />
46 + <fw:InterfaceType Value="[INTERFACETYPE2]" />
47 + <fw:Interface Name="[INTERFACE1]" />
48 + <fw:Interface Name="[INTERFACE2]" />
49 + </fw:FirewallException>
50 + </Component>
51 + </ComponentGroup>
52 + </Fragment>
53 +</Wix>
src/ext/Firewall/test/WixToolsetTest.Firewall/TestData/UsingProperties/example.txt new
+1
@@ -0,0 +1 @@
1 +This is example.txt.
\ No newline at end of file
src/ext/Firewall/test/WixToolsetTest.Firewall/WixToolsetTest.Firewall.csproj
+2
@@ -5,6 +5,8 @@
5 <PropertyGroup>
6 <TargetFramework>net6.0</TargetFramework>
7 <IsWixTestProject>true</IsWixTestProject>
8 + <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
9 + <GenerateTargetFrameworkAttribute>false</GenerateTargetFrameworkAttribute>
10 </PropertyGroup>
11
12 <ItemGroup>
src/ext/Firewall/wixext/FirewallCompiler.cs
+563 -60
@@ -35,7 +35,7 @@ namespace WixToolset.Firewall
35 switch (element.Name.LocalName)
36 {
37 case "FirewallException":
38 - this.ParseFirewallExceptionElement(intermediate, section, element, fileComponentId, fileId);
38 + this.ParseFirewallExceptionElement(intermediate, section, parentElement, element, fileComponentId, fileId, null);
39 break;
40 default:
41 this.ParseHelper.UnexpectedElement(parentElement, element);
@@ -48,7 +48,35 @@ namespace WixToolset.Firewall
48 switch (element.Name.LocalName)
49 {
50 case "FirewallException":
51 - this.ParseFirewallExceptionElement(intermediate, section, element, componentId, null);
51 + this.ParseFirewallExceptionElement(intermediate, section, parentElement, element, componentId, null, null);
52 + break;
53 + default:
54 + this.ParseHelper.UnexpectedElement(parentElement, element);
55 + break;
56 + }
57 + break;
58 + case "ServiceConfig":
59 + var serviceConfigName = context["ServiceConfigServiceName"];
60 + var serviceConfigComponentId = context["ServiceConfigComponentId"];
61 +
62 + switch (element.Name.LocalName)
63 + {
64 + case "FirewallException":
65 + this.ParseFirewallExceptionElement(intermediate, section, parentElement, element, serviceConfigComponentId, null, serviceConfigName);
66 + break;
67 + default:
68 + this.ParseHelper.UnexpectedElement(parentElement, element);
69 + break;
70 + }
71 + break;
72 + case "ServiceInstall":
73 + var serviceInstallName = context["ServiceInstallName"];
74 + var serviceInstallComponentId = context["ServiceInstallComponentId"];
75 +
76 + switch (element.Name.LocalName)
77 + {
78 + case "FirewallException":
79 + this.ParseFirewallExceptionElement(intermediate, section, parentElement, element, serviceInstallComponentId, null, serviceInstallName);
80 break;
81 default:
82 this.ParseHelper.UnexpectedElement(parentElement, element);
@@ -64,10 +92,12 @@ namespace WixToolset.Firewall
92 /// <summary>
93 /// Parses a FirewallException element.
94 /// </summary>
95 + /// <param name="parentElement">The parent element of the one being parsed.</param>
96 /// <param name="element">The element to parse.</param>
97 /// <param name="componentId">Identifier of the component that owns this firewall exception.</param>
98 /// <param name="fileId">The file identifier of the parent element (null if nested under Component).</param>
70 - private void ParseFirewallExceptionElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string fileId)
99 + /// <param name="serviceName">The service name of the parent element (null if not nested under ServiceConfig or ServiceInstall).</param>
100 + private void ParseFirewallExceptionElement(Intermediate intermediate, IntermediateSection section, XElement parentElement, XElement element, string componentId, string fileId, string serviceName)
101 {
102 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
103 Identifier id = null;
@@ -76,12 +106,32 @@ namespace WixToolset.Firewall
106 string file = null;
107 string program = null;
108 string port = null;
79 - int? protocol = null;
80 - int? profile = null;
109 + string protocol = null;
110 + string profile = null;
111 string scope = null;
112 string remoteAddresses = null;
113 string description = null;
114 int? direction = null;
115 + string protocolValue = null;
116 + string action = null;
117 + string edgeTraversal = null;
118 + string enabled = null;
119 + string grouping = null;
120 + string icmpTypesAndCodes = null;
121 + string interfaces = null;
122 + string interfaceValue = null;
123 + string interfaceTypes = null;
124 + string interfaceTypeValue = null;
125 + string localScope = null;
126 + string localAddresses = null;
127 + string remotePort = null;
128 + string service = null;
129 + string localAppPackageId = null;
130 + string localUserAuthorizedList = null;
131 + string localUserOwner = null;
132 + string remoteMachineAuthorizedList = null;
133 + string remoteUserAuthorizedList = null;
134 + string secureFlags = null;
135
136 foreach (var attrib in element.Attributes())
137 {
@@ -96,9 +146,9 @@ namespace WixToolset.Firewall
146 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
147 break;
148 case "File":
99 - if (null != fileId)
149 + if (fileId != null)
150 {
101 - this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, "File", "File"));
151 + this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, "File", parentElement.Name.LocalName));
152 }
153 else
154 {
@@ -106,15 +156,31 @@ namespace WixToolset.Firewall
156 }
157 break;
158 case "IgnoreFailure":
109 - if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
159 + if (this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) == YesNoType.Yes)
160 {
161 attributes |= 0x1; // feaIgnoreFailures
162 }
163 break;
164 + case "OnUpdate":
165 + var onupdate = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
166 + switch (onupdate)
167 + {
168 + case "DoNothing":
169 + attributes |= 0x2; // feaIgnoreUpdates
170 + break;
171 + case "EnableOnly":
172 + attributes |= 0x4; // feaEnableOnUpdate
173 + break;
174 +
175 + default:
176 + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "OnUpdate", onupdate, "EnableOnly", "DoNothing"));
177 + break;
178 + }
179 + break;
180 case "Program":
115 - if (null != fileId)
181 + if (fileId != null)
182 {
117 - this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, "Program", "File"));
183 + this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, "Program", parentElement.Name.LocalName));
184 }
185 else
186 {
@@ -125,22 +191,28 @@ namespace WixToolset.Firewall
191 port = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
192 break;
193 case "Protocol":
128 - var protocolValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
194 + protocolValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
195 switch (protocolValue)
196 {
197 + case FirewallConstants.IntegerNotSetString:
198 + break;
199 +
200 case "tcp":
132 - protocol = FirewallConstants.NET_FW_IP_PROTOCOL_TCP;
201 + protocol = FirewallConstants.NET_FW_IP_PROTOCOL_TCP.ToString();
202 break;
203 case "udp":
135 - protocol = FirewallConstants.NET_FW_IP_PROTOCOL_UDP;
204 + protocol = FirewallConstants.NET_FW_IP_PROTOCOL_UDP.ToString();
205 break;
206 +
207 default:
138 - int parsedProtocol;
139 - if (!Int32.TryParse(protocolValue, out parsedProtocol) || parsedProtocol > 255 || parsedProtocol < 0)
208 + protocol = protocolValue;
209 + if (!this.ParseHelper.ContainsProperty(protocolValue))
210 {
141 - this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "Protocol", protocolValue, "tcp", "udp", "0-255"));
211 + if (!Int32.TryParse(protocolValue, out var parsedProtocol) || parsedProtocol > 255 || parsedProtocol < 0)
212 + {
213 + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "Protocol", protocolValue, "tcp", "udp", "0-255"));
214 + }
215 }
143 - protocol = parsedProtocol;
216 break;
217 }
218 break;
@@ -167,7 +239,11 @@ namespace WixToolset.Firewall
239 remoteAddresses = "DefaultGateway";
240 break;
241 default:
170 - this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "Scope", scope, "any", "localSubnet", "DNS", "DHCP", "WINS", "defaultGateway"));
242 + remoteAddresses = scope;
243 + if (!this.ParseHelper.ContainsProperty(scope))
244 + {
245 + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "Scope", scope, "any", "localSubnet", "DNS", "DHCP", "WINS", "defaultGateway"));
246 + }
247 break;
248 }
249 break;
@@ -176,19 +252,23 @@ namespace WixToolset.Firewall
252 switch (profileValue)
253 {
254 case "domain":
179 - profile = FirewallConstants.NET_FW_PROFILE2_DOMAIN;
255 + profile = FirewallConstants.NET_FW_PROFILE2_DOMAIN.ToString();
256 break;
257 case "private":
182 - profile = FirewallConstants.NET_FW_PROFILE2_PRIVATE;
258 + profile = FirewallConstants.NET_FW_PROFILE2_PRIVATE.ToString();
259 break;
260 case "public":
185 - profile = FirewallConstants.NET_FW_PROFILE2_PUBLIC;
261 + profile = FirewallConstants.NET_FW_PROFILE2_PUBLIC.ToString();
262 break;
263 case "all":
188 - profile = FirewallConstants.NET_FW_PROFILE2_ALL;
264 + profile = FirewallConstants.NET_FW_PROFILE2_ALL.ToString();
265 break;
266 default:
191 - this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "Profile", profileValue, "domain", "private", "public", "all"));
267 + profile = profileValue;
268 + if (!this.ParseHelper.ContainsProperty(profileValue))
269 + {
270 + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "Profile", profileValue, "domain", "private", "public", "all"));
271 + }
272 break;
273 }
274 break;
@@ -200,6 +280,196 @@ namespace WixToolset.Firewall
280 ? FirewallConstants.NET_FW_RULE_DIR_OUT
281 : FirewallConstants.NET_FW_RULE_DIR_IN;
282 break;
283 + case "Action":
284 + action = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
285 + switch (action)
286 + {
287 + case "Block":
288 + action = "0";
289 + break;
290 + case "Allow":
291 + action = "1";
292 + break;
293 +
294 + default:
295 + if (!this.ParseHelper.ContainsProperty(action))
296 + {
297 + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "Action", action, "Allow", "Block"));
298 + }
299 + break;
300 + }
301 + break;
302 + case "EdgeTraversal":
303 + edgeTraversal = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
304 + switch (edgeTraversal)
305 + {
306 + case "Deny":
307 + edgeTraversal = FirewallConstants.NET_FW_EDGE_TRAVERSAL_TYPE_DENY.ToString();
308 + break;
309 + case "Allow":
310 + edgeTraversal = FirewallConstants.NET_FW_EDGE_TRAVERSAL_TYPE_ALLOW.ToString();
311 + break;
312 + case "DeferToApp":
313 + attributes |= 0x8; // feaAddINetFwRule2
314 + edgeTraversal = FirewallConstants.NET_FW_EDGE_TRAVERSAL_TYPE_DEFER_TO_APP.ToString();
315 + break;
316 + case "DeferToUser":
317 + attributes |= 0x8; // feaAddINetFwRule2
318 + edgeTraversal = FirewallConstants.NET_FW_EDGE_TRAVERSAL_TYPE_DEFER_TO_USER.ToString();
319 + break;
320 +
321 + default:
322 + if (!this.ParseHelper.ContainsProperty(edgeTraversal))
323 + {
324 + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "EdgeTraversal", edgeTraversal, "Allow", "DeferToApp", "DeferToUser", "Deny"));
325 + }
326 + break;
327 + }
328 + break;
329 + case "Enabled":
330 + enabled = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
331 + if (!this.ParseHelper.ContainsProperty(enabled))
332 + {
333 + switch (this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
334 + {
335 + case YesNoType.Yes:
336 + enabled = "1";
337 + break;
338 + case YesNoType.No:
339 + enabled = "0";
340 + break;
341 +
342 + default:
343 + this.Messaging.Write(ErrorMessages.IllegalYesNoValue(sourceLineNumbers, element.Name.LocalName, "Enabled", enabled));
344 + break;
345 + }
346 + }
347 + break;
348 + case "Grouping":
349 + grouping = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
350 + break;
351 + case "IcmpTypesAndCodes":
352 + icmpTypesAndCodes = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
353 + break;
354 + case "Interface":
355 + interfaceValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
356 + interfaces = interfaceValue;
357 + break;
358 + case "InterfaceType":
359 + interfaceTypeValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
360 + switch (interfaceTypeValue)
361 + {
362 + case "RemoteAccess":
363 + case "Wireless":
364 + case "Lan":
365 + case "All":
366 + break;
367 +
368 + default:
369 + if (!this.ParseHelper.ContainsProperty(interfaceTypeValue))
370 + {
371 + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "InterfaceType", interfaceTypeValue, "RemoteAccess", "Wireless", "Lan", "All"));
372 + }
373 + break;
374 + }
375 + interfaceTypes = interfaceTypeValue;
376 + break;
377 + case "LocalScope":
378 + localScope = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
379 + switch (localScope)
380 + {
381 + case "any":
382 + localAddresses = "*";
383 + break;
384 + case "localSubnet":
385 + localAddresses = "LocalSubnet";
386 + break;
387 + case "DNS":
388 + localAddresses = "dns";
389 + break;
390 + case "DHCP":
391 + localAddresses = "dhcp";
392 + break;
393 + case "WINS":
394 + localAddresses = "wins";
395 + break;
396 + case "defaultGateway":
397 + localAddresses = "DefaultGateway";
398 + break;
399 +
400 + default:
401 + if (!this.ParseHelper.ContainsProperty(localScope))
402 + {
403 + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "LocalScope", localScope, "any", "localSubnet", "DNS", "DHCP", "WINS", "defaultGateway"));
404 + }
405 + else
406 + {
407 + localAddresses = localScope;
408 + }
409 + break;
410 + }
411 + break;
412 + case "RemotePort":
413 + remotePort = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
414 + break;
415 + case "Service":
416 + if (serviceName != null)
417 + {
418 + this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, "Service", parentElement.Name.LocalName));
419 + }
420 + else
421 + {
422 + service = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
423 + }
424 + break;
425 + case "LocalAppPackageId":
426 + localAppPackageId = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
427 + attributes |= 0x10; // feaAddINetFwRule3
428 + break;
429 + case "LocalUserAuthorizedList":
430 + localUserAuthorizedList = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
431 + attributes |= 0x10; // feaAddINetFwRule3
432 + break;
433 + case "LocalUserOwner":
434 + localUserOwner = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
435 + attributes |= 0x10; // feaAddINetFwRule3
436 + break;
437 + case "RemoteMachineAuthorizedList":
438 + remoteMachineAuthorizedList = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
439 + attributes |= 0x10; // feaAddINetFwRule3
440 + break;
441 + case "RemoteUserAuthorizedList":
442 + remoteUserAuthorizedList = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
443 + attributes |= 0x10; // feaAddINetFwRule3
444 + break;
445 + case "IPSecSecureFlags":
446 + secureFlags = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
447 + attributes |= 0x10; // feaAddINetFwRule3
448 + if (!this.ParseHelper.ContainsProperty(secureFlags))
449 + {
450 + switch (secureFlags)
451 + {
452 + case "None":
453 + secureFlags = "0";
454 + break;
455 + case "NoEncapsulation":
456 + secureFlags = "1";
457 + break;
458 + case "WithIntegrity":
459 + secureFlags = "2";
460 + break;
461 + case "NegotiateEncryption":
462 + secureFlags = "3";
463 + break;
464 + case "Encrypt":
465 + secureFlags = "4";
466 + break;
467 + default:
468 + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "IPSecSecureFlags", secureFlags, "None", "NoEncapsulation", "WithIntegrity", "NegotiateEncryption", "Encrypt"));
469 + break;
470 + }
471 + }
472 + break;
473 default:
474 this.ParseHelper.UnexpectedAttribute(element, attrib);
475 break;
@@ -211,7 +481,7 @@ namespace WixToolset.Firewall
481 }
482 }
483
214 - // parse RemoteAddress children
484 + // parse children
485 foreach (var child in element.Elements())
486 {
487 if (this.Namespace == child.Name.Namespace)
@@ -219,7 +489,7 @@ namespace WixToolset.Firewall
489 switch (child.Name.LocalName)
490 {
491 case "RemoteAddress":
222 - if (null != scope)
492 + if (scope != null)
493 {
494 this.Messaging.Write(FirewallErrors.IllegalRemoteAddressWithScopeAttribute(sourceLineNumbers));
495 }
@@ -228,6 +498,37 @@ namespace WixToolset.Firewall
498 this.ParseRemoteAddressElement(intermediate, section, child, ref remoteAddresses);
499 }
500 break;
501 + case "Interface":
502 + if (interfaceValue != null)
503 + {
504 + this.Messaging.Write(FirewallErrors.IllegalInterfaceWithInterfaceAttribute(sourceLineNumbers));
505 + }
506 + else
507 + {
508 + this.ParseInterfaceElement(intermediate, section, child, ref interfaces);
509 + }
510 + break;
511 + case "InterfaceType":
512 + if (interfaceTypeValue != null)
513 + {
514 + this.Messaging.Write(FirewallErrors.IllegalInterfaceTypeWithInterfaceTypeAttribute(sourceLineNumbers));
515 + }
516 + else
517 + {
518 + this.ParseInterfaceTypeElement(intermediate, section, child, ref interfaceTypes);
519 + }
520 + break;
521 + case "LocalAddress":
522 + if (localScope != null)
523 + {
524 + this.Messaging.Write(FirewallErrors.IllegalLocalAddressWithLocalScopeAttribute(sourceLineNumbers));
525 + }
526 + else
527 + {
528 + this.ParseLocalAddressElement(intermediate, section, child, ref localAddresses);
529 + }
530 + break;
531 +
532 default:
533 this.ParseHelper.UnexpectedElement(element, child);
534 break;
@@ -239,54 +540,84 @@ namespace WixToolset.Firewall
540 }
541 }
542
242 - if (null == id)
543 + if (id == null)
544 {
244 - id = this.ParseHelper.CreateIdentifier("fex", name, remoteAddresses, componentId);
545 + // firewall rule names are meant to be unique
546 + id = this.ParseHelper.CreateIdentifier("fex", name, componentId);
547 }
548
549 // Name is required
248 - if (null == name)
550 + if (name == null)
551 {
552 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
553 }
554
253 - // Scope or child RemoteAddress(es) are required
254 - if (null == remoteAddresses)
555 + if (service == null)
556 {
256 - this.Messaging.Write(ErrorMessages.ExpectedAttributeOrElement(sourceLineNumbers, element.Name.LocalName, "Scope", "RemoteAddress"));
557 + service = serviceName;
558 }
559
560 // can't have both Program and File
260 - if (null != program && null != file)
561 + if (program != null && file != null)
562 {
563 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "File", "Program"));
564 }
565
265 - // must be nested under File, have File or Program attributes, or have Port attribute
266 - if (String.IsNullOrEmpty(fileId) && String.IsNullOrEmpty(file) && String.IsNullOrEmpty(program) && String.IsNullOrEmpty(port))
566 + // Defer to user edge traversal setting can only be used in a firewall rule where program path and TCP/UDP protocol are specified with no additional conditions.
567 + if (edgeTraversal == FirewallConstants.NET_FW_EDGE_TRAVERSAL_TYPE_DEFER_TO_USER.ToString())
568 {
268 - this.Messaging.Write(FirewallErrors.NoExceptionSpecified(sourceLineNumbers));
269 - }
569 + if (protocol != null && !(protocol == FirewallConstants.NET_FW_IP_PROTOCOL_TCP.ToString() || protocol == FirewallConstants.NET_FW_IP_PROTOCOL_UDP.ToString()))
570 + {
571 + this.Messaging.Write(ErrorMessages.IllegalAttributeValueWithLegalList(sourceLineNumbers, element.Name.LocalName, "Protocol", protocolValue, "tcp,udp"));
572 + }
573
271 - // Ports can only be specified if the protocol is TCP or UDP.
272 - if (!String.IsNullOrEmpty(port) && protocol.HasValue)
273 - {
274 - switch(protocol.Value)
574 + if (String.IsNullOrEmpty(fileId) && String.IsNullOrEmpty(file) && String.IsNullOrEmpty(program))
575 {
276 - case FirewallConstants.NET_FW_IP_PROTOCOL_TCP:
277 - case FirewallConstants.NET_FW_IP_PROTOCOL_UDP:
278 - break;
576 + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Program", "EdgeTraversal", "DeferToUser"));
577 + }
578
280 - default:
281 - this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "Port", "Protocol", protocol.Value.ToString()));
282 - break;
579 + if (port != null)
580 + {
581 + this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "Port", "EdgeTraversal", "DeferToUser"));
582 + }
583 +
584 + if (remotePort != null)
585 + {
586 + this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "RemotePort", "EdgeTraversal", "DeferToUser"));
587 + }
588 +
589 + if (localScope != null)
590 + {
591 + this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "LocalScope", "EdgeTraversal", "DeferToUser"));
592 + }
593 +
594 + if (scope != null)
595 + {
596 + this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "Scope", "EdgeTraversal", "DeferToUser"));
597 + }
598 +
599 + if (profile != null)
600 + {
601 + this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "Profile", "EdgeTraversal", "DeferToUser"));
602 + }
603 +
604 + if (service != null)
605 + {
606 + if (serviceName != null)
607 + {
608 + this.Messaging.Write(ErrorMessages.IllegalAttributeValueWhenNested(sourceLineNumbers, element.Name.LocalName, "EdgeTraversal", "DeferToUser", parentElement.Name.LocalName));
609 + }
610 + else
611 + {
612 + this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "Service", "EdgeTraversal", "DeferToUser"));
613 + }
614 }
615 }
616
617 if (!this.Messaging.EncounteredError)
618 {
619 // at this point, File attribute and File parent element are treated the same
289 - if (null != file)
620 + if (file != null)
621 {
622 fileId = file;
623 }
@@ -295,28 +626,38 @@ namespace WixToolset.Firewall
626 {
627 Name = name,
628 RemoteAddresses = remoteAddresses,
298 - Profile = profile ?? FirewallConstants.NET_FW_PROFILE2_ALL,
629 ComponentRef = componentId,
630 Description = description,
631 Direction = direction ?? FirewallConstants.NET_FW_RULE_DIR_IN,
632 + Action = action ?? FirewallConstants.IntegerNotSetString,
633 + EdgeTraversal = edgeTraversal ?? FirewallConstants.IntegerNotSetString,
634 + Enabled = enabled ?? FirewallConstants.IntegerNotSetString,
635 + Grouping = grouping,
636 + IcmpTypesAndCodes = icmpTypesAndCodes,
637 + Interfaces = interfaces,
638 + InterfaceTypes = interfaceTypes,
639 + LocalAddresses = localAddresses,
640 + Port = port,
641 + Profile = profile ?? FirewallConstants.IntegerNotSetString,
642 + Protocol = protocol ?? FirewallConstants.IntegerNotSetString,
643 + RemotePort = remotePort,
644 + ServiceName = service,
645 + LocalAppPackageId = localAppPackageId,
646 + LocalUserAuthorizedList = localUserAuthorizedList,
647 + LocalUserOwner = localUserOwner,
648 + RemoteMachineAuthorizedList = remoteMachineAuthorizedList,
649 + RemoteUserAuthorizedList = remoteUserAuthorizedList,
650 + SecureFlags = secureFlags ?? FirewallConstants.IntegerNotSetString,
651 });
652
304 - if (!String.IsNullOrEmpty(port))
653 + if (String.IsNullOrEmpty(protocol))
654 {
306 - symbol.Port = port;
307 -
308 - if (!protocol.HasValue)
655 + if (!String.IsNullOrEmpty(port) || !String.IsNullOrEmpty(remotePort))
656 {
310 - // default protocol is "TCP"
311 - protocol = FirewallConstants.NET_FW_IP_PROTOCOL_TCP;
657 + symbol.Protocol = FirewallConstants.NET_FW_IP_PROTOCOL_TCP.ToString();
658 }
659 }
660
315 - if (protocol.HasValue)
316 - {
317 - symbol.Protocol = protocol.Value;
318 - }
319 -
661 if (!String.IsNullOrEmpty(fileId))
662 {
663 symbol.Program = $"[#{fileId}]";
@@ -327,7 +668,7 @@ namespace WixToolset.Firewall
668 symbol.Program = program;
669 }
670
330 - if (CompilerConstants.IntegerNotSet != attributes)
671 + if (attributes != CompilerConstants.IntegerNotSet)
672 {
673 symbol.Attributes = attributes;
674 }
@@ -382,5 +723,167 @@ namespace WixToolset.Firewall
723 }
724 }
725 }
726 +
727 + /// <summary>
728 + /// Parses an Interface element
729 + /// </summary>
730 + /// <param name="element">The element to parse.</param>
731 + private void ParseInterfaceElement(Intermediate intermediate, IntermediateSection section, XElement element, ref string interfaces)
732 + {
733 + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
734 + string name = null;
735 +
736 + // no attributes
737 + foreach (var attrib in element.Attributes())
738 + {
739 + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
740 + {
741 + switch (attrib.Name.LocalName)
742 + {
743 + case "Name":
744 + name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
745 + break;
746 + }
747 + }
748 + else
749 + {
750 + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
751 + }
752 + }
753 +
754 + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
755 +
756 + if (String.IsNullOrEmpty(name))
757 + {
758 + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
759 + }
760 + else
761 + {
762 + if (String.IsNullOrEmpty(interfaces))
763 + {
764 + interfaces = name;
765 + }
766 + else
767 + {
768 + interfaces = String.Concat(interfaces, FirewallConstants.FORBIDDEN_FIREWALL_CHAR, name);
769 + }
770 + }
771 + }
772 +
773 + /// <summary>
774 + /// Parses an InterfaceType element
775 + /// </summary>
776 + /// <param name="element">The element to parse.</param>
777 + private void ParseInterfaceTypeElement(Intermediate intermediate, IntermediateSection section, XElement element, ref string interfaceTypes)
778 + {
779 + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
780 + string value = null;
781 +
782 + // no attributes
783 + foreach (var attrib in element.Attributes())
784 + {
785 + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
786 + {
787 + switch (attrib.Name.LocalName)
788 + {
789 + case "Value":
790 + value = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
791 + break;
792 + }
793 + }
794 + else
795 + {
796 + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
797 + }
798 + }
799 +
800 + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
801 +
802 + if (String.IsNullOrEmpty(value))
803 + {
804 + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Value"));
805 + }
806 + else
807 + {
808 + switch (value)
809 + {
810 + case "RemoteAccess":
811 + case "Wireless":
812 + case "Lan":
813 + case "All":
814 + break;
815 +
816 + default:
817 + if (!this.ParseHelper.ContainsProperty(value))
818 + {
819 + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "Value", value, "RemoteAccess", "Wireless", "Lan", "All"));
820 + value = null;
821 + }
822 + break;
823 + }
824 +
825 + if (String.IsNullOrEmpty(interfaceTypes))
826 + {
827 + interfaceTypes = value;
828 + }
829 + else if (interfaceTypes.Contains("All"))
830 + {
831 + if (value != "All")
832 + {
833 + this.Messaging.Write(FirewallErrors.IllegalInterfaceTypeWithInterfaceTypeAll(sourceLineNumbers));
834 + }
835 + }
836 + else if(!String.IsNullOrEmpty(value))
837 + {
838 + interfaceTypes = String.Concat(interfaceTypes, ",", value);
839 + }
840 + }
841 + }
842 +
843 + /// <summary>
844 + /// Parses a RemoteAddress element
845 + /// </summary>
846 + /// <param name="element">The element to parse.</param>
847 + private void ParseLocalAddressElement(Intermediate intermediate, IntermediateSection section, XElement element, ref string localAddresses)
848 + {
849 + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
850 + string address = null;
851 +
852 + // no attributes
853 + foreach (var attrib in element.Attributes())
854 + {
855 + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
856 + {
857 + switch (attrib.Name.LocalName)
858 + {
859 + case "Value":
860 + address = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
861 + break;
862 + }
863 + }
864 + else
865 + {
866 + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
867 + }
868 + }
869 +
870 + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
871 +
872 + if (String.IsNullOrEmpty(address))
873 + {
874 + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Value"));
875 + }
876 + else
877 + {
878 + if (String.IsNullOrEmpty(localAddresses))
879 + {
880 + localAddresses = address;
881 + }
882 + else
883 + {
884 + localAddresses = String.Concat(localAddresses, ",", address);
885 + }
886 + }
887 + }
888 }
889 }
src/ext/Firewall/wixext/FirewallConstants.cs
+17
@@ -9,6 +9,11 @@ namespace WixToolset.Firewall
9 internal static readonly XNamespace Namespace = "http://wixtoolset.org/schemas/v4/wxs/firewall";
10 internal static readonly XName FirewallExceptionName = Namespace + "FirewallException";
11 internal static readonly XName RemoteAddressName = Namespace + "RemoteAddress";
12 + internal static readonly XName InterfaceName = Namespace + "Interface";
13 + internal static readonly XName InterfaceTypeName = Namespace + "InterfaceType";
14 + internal static readonly XName LocalAddressName = Namespace + "LocalAddress";
15 +
16 + internal const string IntegerNotSetString = "-2147483648";
17
18 // from icftypes.h
19 public const int NET_FW_RULE_DIR_IN = 1;
@@ -21,5 +26,17 @@ namespace WixToolset.Firewall
26 public const int NET_FW_PROFILE2_PRIVATE = 0x0002;
27 public const int NET_FW_PROFILE2_PUBLIC = 0x0004;
28 public const int NET_FW_PROFILE2_ALL = 0x7FFFFFFF;
29 +
30 + // from icftypes.h
31 + public const int NET_FW_EDGE_TRAVERSAL_TYPE_DENY = 0;
32 + public const int NET_FW_EDGE_TRAVERSAL_TYPE_ALLOW = 1;
33 + public const int NET_FW_EDGE_TRAVERSAL_TYPE_DEFER_TO_APP = 2;
34 + public const int NET_FW_EDGE_TRAVERSAL_TYPE_DEFER_TO_USER = 3;
35 +
36 + /// <summary>
37 + /// Firewall rules are stored in the registry.<br/>
38 + /// The pipe character is used to split firewall rule attributes, so is not permitted in any of them.
39 + /// </summary>
40 + public const char FORBIDDEN_FIREWALL_CHAR = '|';
41 }
42 }
src/ext/Firewall/wixext/FirewallDecompiler.cs
+300 -17
@@ -8,6 +8,8 @@ namespace WixToolset.Firewall
8 using WixToolset.Data;
9 using WixToolset.Data.WindowsInstaller;
10 using WixToolset.Extensibility;
11 + using WixToolset.Extensibility.Data;
12 + using WixToolset.Extensibility.Services;
13
14 /// <summary>
15 /// The decompiler for the WiX Toolset Firewall Extension.
@@ -16,6 +18,14 @@ namespace WixToolset.Firewall
18 {
19 public override IReadOnlyCollection<TableDefinition> TableDefinitions => FirewallTableDefinitions.All;
20
21 + private IParseHelper ParseHelper { get; set; }
22 +
23 + public override void PreDecompile(IWindowsInstallerDecompileContext context, IWindowsInstallerDecompilerHelper helper)
24 + {
25 + base.PreDecompile(context, helper);
26 + this.ParseHelper = context.ServiceProvider.GetService<IParseHelper>();
27 + }
28 +
29 /// <summary>
30 /// Called at the beginning of the decompilation of a database.
31 /// </summary>
@@ -32,6 +42,8 @@ namespace WixToolset.Firewall
42 {
43 switch (table.Name)
44 {
45 + case "WixFirewallException":
46 + case "Wix4FirewallException":
47 case "Wix5FirewallException":
48 this.DecompileWixFirewallExceptionTable(table);
49 break;
@@ -57,7 +69,7 @@ namespace WixToolset.Firewall
69 /// <param name="table">The table to decompile.</param>
70 private void DecompileWixFirewallExceptionTable(Table table)
71 {
60 - foreach (Row row in table.Rows)
72 + foreach (var row in table.Rows)
73 {
74 var firewallException = new XElement(FirewallConstants.FirewallExceptionName,
75 new XAttribute("Id", row.FieldAsString(0)),
@@ -90,13 +102,20 @@ namespace WixToolset.Firewall
102 firewallException.Add(new XAttribute("Scope", "defaultGateway"));
103 break;
104 default:
93 - FirewallDecompiler.AddRemoteAddress(firewallException, addresses[0]);
105 + if (this.ParseHelper.ContainsProperty(addresses[0]))
106 + {
107 + firewallException.Add(new XAttribute("Scope", addresses[0]));
108 + }
109 + else
110 + {
111 + FirewallDecompiler.AddRemoteAddress(firewallException, addresses[0]);
112 + }
113 break;
114 }
115 }
116 else
117 {
99 - foreach (string address in addresses)
118 + foreach (var address in addresses)
119 {
120 FirewallDecompiler.AddRemoteAddress(firewallException, address);
121 }
@@ -110,16 +129,19 @@ namespace WixToolset.Firewall
129
130 if (!row.IsColumnEmpty(4))
131 {
113 - switch (Convert.ToInt32(row[4]))
132 + switch (row.FieldAsString(4))
133 {
115 - case FirewallConstants.NET_FW_IP_PROTOCOL_TCP:
134 + case FirewallConstants.IntegerNotSetString:
135 + break;
136 + case "6":
137 firewallException.Add(new XAttribute("Protocol", "tcp"));
138 break;
118 - case FirewallConstants.NET_FW_IP_PROTOCOL_UDP:
139 + case "17":
140 firewallException.Add(new XAttribute("Protocol", "udp"));
141 break;
142 +
143 default:
122 - firewallException.Add(new XAttribute("Protocol", row[4]));
144 + firewallException.Add(new XAttribute("Protocol", row.FieldAsString(4)));
145 break;
146 }
147 }
@@ -131,26 +153,44 @@ namespace WixToolset.Firewall
153
154 if (!row.IsColumnEmpty(6))
155 {
134 - var attr = Convert.ToInt32(row[6]);
135 - AttributeIfNotNull("IgnoreFailure", (attr & 0x1) == 0x1);
156 + var attr = row.FieldAsInteger(6);
157 + if ((attr & 0x1) == 0x1)
158 + {
159 + AttributeIfNotNull("IgnoreFailure", true);
160 + }
161 +
162 + if ((attr & 0x2) == 0x2)
163 + {
164 + firewallException.Add(new XAttribute("OnUpdate", "DoNothing"));
165 + }
166 + else if ((attr & 0x4) == 0x4)
167 + {
168 + firewallException.Add(new XAttribute("OnUpdate", "EnableOnly"));
169 + }
170 }
171
172 if (!row.IsColumnEmpty(7))
173 {
140 - switch (Convert.ToInt32(row[7]))
174 + switch (row.FieldAsString(7))
175 {
142 - case FirewallConstants.NET_FW_PROFILE2_DOMAIN:
176 + case FirewallConstants.IntegerNotSetString:
177 + break;
178 + case "1":
179 firewallException.Add(new XAttribute("Profile", "domain"));
180 break;
145 - case FirewallConstants.NET_FW_PROFILE2_PRIVATE:
181 + case "2":
182 firewallException.Add(new XAttribute("Profile", "private"));
183 break;
148 - case FirewallConstants.NET_FW_PROFILE2_PUBLIC:
184 + case "4":
185 firewallException.Add(new XAttribute("Profile", "public"));
186 break;
151 - case FirewallConstants.NET_FW_PROFILE2_ALL:
187 + case "2147483647":
188 firewallException.Add(new XAttribute("Profile", "all"));
189 break;
190 +
191 + default:
192 + firewallException.Add(new XAttribute("Profile", row.FieldAsString(7)));
193 + break;
194 }
195 }
196
@@ -164,8 +204,6 @@ namespace WixToolset.Firewall
204 switch (Convert.ToInt32(row[10]))
205 {
206 case FirewallConstants.NET_FW_RULE_DIR_IN:
167 -
168 - firewallException.Add(AttributeIfNotNull("Outbound", false));
207 break;
208 case FirewallConstants.NET_FW_RULE_DIR_OUT:
209 firewallException.Add(AttributeIfNotNull("Outbound", true));
@@ -173,6 +211,224 @@ namespace WixToolset.Firewall
211 }
212 }
213
214 + // Introduced in 5.0.0
215 + if (row.Fields.Length > 11)
216 + {
217 + if (!row.IsColumnEmpty(11))
218 + {
219 + var action = row.FieldAsString(11);
220 + switch (action)
221 + {
222 + case FirewallConstants.IntegerNotSetString:
223 + break;
224 + case "1":
225 + firewallException.Add(new XAttribute("Action", "Allow"));
226 + break;
227 + case "0":
228 + firewallException.Add(new XAttribute("Action", "Block"));
229 + break;
230 + default:
231 + firewallException.Add(new XAttribute("Action", action));
232 + break;
233 + }
234 + }
235 +
236 + if (!row.IsColumnEmpty(12))
237 + {
238 + var edgeTraversal = row.FieldAsString(12);
239 + switch (edgeTraversal)
240 + {
241 + case FirewallConstants.IntegerNotSetString:
242 + break;
243 + case "0":
244 + firewallException.Add(new XAttribute("EdgeTraversal", "Deny"));
245 + break;
246 + case "1":
247 + firewallException.Add(new XAttribute("EdgeTraversal", "Allow"));
248 + break;
249 + case "2":
250 + firewallException.Add(new XAttribute("EdgeTraversal", "DeferToApp"));
251 + break;
252 + case "3":
253 + firewallException.Add(new XAttribute("EdgeTraversal", "DeferToUser"));
254 + break;
255 + default:
256 + firewallException.Add(new XAttribute("EdgeTraversal", edgeTraversal));
257 + break;
258 + }
259 + }
260 +
261 + if (!row.IsColumnEmpty(13))
262 + {
263 + var enabled = row.FieldAsString(13);
264 + switch (enabled)
265 + {
266 + case FirewallConstants.IntegerNotSetString:
267 + break;
268 + case "1":
269 + firewallException.Add(new XAttribute("Enabled", "yes"));
270 + break;
271 + case "0":
272 + firewallException.Add(new XAttribute("Enabled", "no"));
273 + break;
274 + default:
275 + firewallException.Add(new XAttribute("Enabled", enabled));
276 + break;
277 + }
278 + }
279 +
280 + if (!row.IsColumnEmpty(14))
281 + {
282 + firewallException.Add(new XAttribute("Grouping", row.FieldAsString(14)));
283 + }
284 +
285 + if (!row.IsColumnEmpty(15))
286 + {
287 + firewallException.Add(new XAttribute("IcmpTypesAndCodes", row.FieldAsString(15)));
288 + }
289 +
290 + if (!row.IsColumnEmpty(16))
291 + {
292 + string[] interfaces = row.FieldAsString(16).Split(new[] { FirewallConstants.FORBIDDEN_FIREWALL_CHAR }, StringSplitOptions.RemoveEmptyEntries);
293 + if (interfaces.Length == 1)
294 + {
295 + firewallException.Add(new XAttribute("Interface", interfaces[0]));
296 + }
297 + else
298 + {
299 + foreach (var interfaceItem in interfaces)
300 + {
301 + FirewallDecompiler.AddInterface(firewallException, interfaceItem);
302 + }
303 + }
304 + }
305 +
306 + if (!row.IsColumnEmpty(17))
307 + {
308 + string[] interfaceTypes = row.FieldAsString(17).Split(',');
309 + if (interfaceTypes.Length == 1)
310 + {
311 + firewallException.Add(new XAttribute("InterfaceType", interfaceTypes[0]));
312 + }
313 + else
314 + {
315 + foreach (var interfaceType in interfaceTypes)
316 + {
317 + FirewallDecompiler.AddInterfaceType(firewallException, interfaceType);
318 + }
319 + }
320 + }
321 +
322 + if (!row.IsColumnEmpty(18))
323 + {
324 + string[] addresses = row.FieldAsString(18).Split(',');
325 + if (addresses.Length == 1)
326 + {
327 + switch (addresses[0])
328 + {
329 + case "*":
330 + firewallException.Add(new XAttribute("LocalScope", "any"));
331 + break;
332 + case "LocalSubnet":
333 + firewallException.Add(new XAttribute("LocalScope", "localSubnet"));
334 + break;
335 + case "dns":
336 + firewallException.Add(new XAttribute("LocalScope", "DNS"));
337 + break;
338 + case "dhcp":
339 + firewallException.Add(new XAttribute("LocalScope", "DHCP"));
340 + break;
341 + case "wins":
342 + firewallException.Add(new XAttribute("LocalScope", "WINS"));
343 + break;
344 + case "DefaultGateway":
345 + firewallException.Add(new XAttribute("LocalScope", "defaultGateway"));
346 + break;
347 + default:
348 + if (this.ParseHelper.ContainsProperty(addresses[0]))
349 + {
350 + firewallException.Add(new XAttribute("LocalScope", addresses[0]));
351 + }
352 + else
353 + {
354 + FirewallDecompiler.AddLocalAddress(firewallException, addresses[0]);
355 + }
356 + break;
357 + }
358 + }
359 + else
360 + {
361 + foreach (var address in addresses)
362 + {
363 + FirewallDecompiler.AddLocalAddress(firewallException, address);
364 + }
365 + }
366 + }
367 +
368 + if (!row.IsColumnEmpty(19))
369 + {
370 + firewallException.Add(new XAttribute("RemotePort", row.FieldAsString(19)));
371 + }
372 +
373 + if (!row.IsColumnEmpty(20))
374 + {
375 + firewallException.Add(new XAttribute("Service", row.FieldAsString(20)));
376 + }
377 +
378 + if (!row.IsColumnEmpty(21))
379 + {
380 + firewallException.Add(new XAttribute("LocalAppPackageId", row.FieldAsString(21)));
381 + }
382 +
383 + if (!row.IsColumnEmpty(22))
384 + {
385 + firewallException.Add(new XAttribute("LocalUserAuthorizedList", row.FieldAsString(22)));
386 + }
387 +
388 + if (!row.IsColumnEmpty(23))
389 + {
390 + firewallException.Add(new XAttribute("LocalUserOwner", row.FieldAsString(23)));
391 + }
392 +
393 + if (!row.IsColumnEmpty(24))
394 + {
395 + firewallException.Add(new XAttribute("RemoteMachineAuthorizedList", row.FieldAsString(24)));
396 + }
397 +
398 + if (!row.IsColumnEmpty(25))
399 + {
400 + firewallException.Add(new XAttribute("RemoteUserAuthorizedList", row.FieldAsString(25)));
401 + }
402 +
403 + if (!row.IsColumnEmpty(26))
404 + {
405 + var secureFlags = row.FieldAsString(26);
406 + switch (secureFlags)
407 + {
408 + case FirewallConstants.IntegerNotSetString:
409 + break;
410 + case "0":
411 + firewallException.Add(new XAttribute("IPSecSecureFlags", "None"));
412 + break;
413 + case "1":
414 + firewallException.Add(new XAttribute("IPSecSecureFlags", "NoEncapsulation"));
415 + break;
416 + case "2":
417 + firewallException.Add(new XAttribute("IPSecSecureFlags", "WithIntegrity"));
418 + break;
419 + case "3":
420 + firewallException.Add(new XAttribute("IPSecSecureFlags", "NegotiateEncryption"));
421 + break;
422 + case "4":
423 + firewallException.Add(new XAttribute("IPSecSecureFlags", "Encrypt"));
424 + break;
425 + default:
426 + firewallException.Add(new XAttribute("IPSecSecureFlags", secureFlags));
427 + break;
428 + }
429 + }
430 + }
431 +
432 this.DecompilerHelper.IndexElement(row, firewallException);
433 }
434 }
@@ -183,7 +439,34 @@ namespace WixToolset.Firewall
439 new XAttribute("Value", address)
440 );
441
186 - firewallException.AddAfterSelf(remoteAddress);
442 + firewallException.Add(remoteAddress);
443 + }
444 +
445 + private static void AddInterfaceType(XElement firewallException, string type)
446 + {
447 + var interfaceType = new XElement(FirewallConstants.InterfaceTypeName,
448 + new XAttribute("Value", type)
449 + );
450 +
451 + firewallException.Add(interfaceType);
452 + }
453 +
454 + private static void AddLocalAddress(XElement firewallException, string address)
455 + {
456 + var localAddress = new XElement(FirewallConstants.LocalAddressName,
457 + new XAttribute("Value", address)
458 + );
459 +
460 + firewallException.Add(localAddress);
461 + }
462 +
463 + private static void AddInterface(XElement firewallException, string value)
464 + {
465 + var interfaceName = new XElement(FirewallConstants.InterfaceName,
466 + new XAttribute("Name", value)
467 + );
468 +
469 + firewallException.Add(interfaceName);
470 }
471
472 private static XAttribute AttributeIfNotNull(string name, bool value)
src/ext/Firewall/wixext/FirewallErrors.cs
+23 -6
@@ -12,11 +12,6 @@ namespace WixToolset.Firewall
12 return Message(sourceLineNumbers, Ids.IllegalRemoteAddressWithScopeAttribute, "The RemoteAddress element cannot be specified because its parent FirewallException already specified the Scope attribute. To use RemoteAddress elements, omit the Scope attribute.");
13 }
14
15 - public static Message NoExceptionSpecified(SourceLineNumber sourceLineNumbers)
16 - {
17 - return Message(sourceLineNumbers, Ids.NoExceptionSpecified, "The FirewallException element doesn't identify the target of the firewall exception. To create an application exception, nest the FirewallException element under a File element or provide a value for the File or Program attributes. To create a port exception, provide a value for the Port attribute.");
18 - }
19 -
15 private static Message Message(SourceLineNumber sourceLineNumber, Ids id, string format, params object[] args)
16 {
17 return new Message(sourceLineNumber, MessageLevel.Error, (int)id, format, args);
@@ -27,10 +22,32 @@ namespace WixToolset.Firewall
22 return new Message(sourceLineNumber, MessageLevel.Error, (int)id, resourceManager, resourceName, args);
23 }
24
25 + public static Message IllegalInterfaceWithInterfaceAttribute(SourceLineNumber sourceLineNumbers)
26 + {
27 + return Message(sourceLineNumbers, Ids.IllegalInterfaceWithInterfaceAttribute, "The Interface element cannot be specified because its parent FirewallException already specified the Interface attribute. To use Interface elements, omit the Interface attribute.");
28 + }
29 +
30 + public static Message IllegalInterfaceTypeWithInterfaceTypeAttribute(SourceLineNumber sourceLineNumbers)
31 + {
32 + return Message(sourceLineNumbers, Ids.IllegalInterfaceTypeWithInterfaceTypeAttribute, "The InterfaceType element cannot be specified because its parent FirewallException already specified the InterfaceType attribute. To use InterfaceType elements, omit the InterfaceType attribute.");
33 + }
34 +
35 + public static Message IllegalInterfaceTypeWithInterfaceTypeAll(SourceLineNumber sourceLineNumbers)
36 + {
37 + return Message(sourceLineNumbers, Ids.IllegalInterfaceTypeWithInterfaceTypeAll, "The InterfaceType element cannot be specified because its parent FirewallException contains another InterfaceType element with value 'All'.");
38 + }
39 + public static Message IllegalLocalAddressWithLocalScopeAttribute(SourceLineNumber sourceLineNumbers)
40 + {
41 + return Message(sourceLineNumbers, Ids.IllegalLocalAddressWithLocalScopeAttribute, "The LocalAddress element cannot be specified because its parent FirewallException already specified the LocalScope attribute. To use LocalAddress elements, omit the LocalScope attribute.");
42 + }
43 +
44 public enum Ids
45 {
46 IllegalRemoteAddressWithScopeAttribute = 6401,
33 - NoExceptionSpecified = 6403,
47 + IllegalInterfaceWithInterfaceAttribute = 6402,
48 + IllegalInterfaceTypeWithInterfaceTypeAttribute = 6404,
49 + IllegalInterfaceTypeWithInterfaceTypeAll = 6405,
50 + IllegalLocalAddressWithLocalScopeAttribute = 6406,
51 }
52 }
53 }
src/ext/Firewall/wixext/FirewallTableDefinitions.cs
+22 -6
@@ -13,15 +13,31 @@ namespace WixToolset.Firewall
13 {
14 new ColumnDefinition("Wix5FirewallException", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "The primary key, a non-localized token.", modularizeType: ColumnModularizeType.Column),
15 new ColumnDefinition("Name", ColumnType.Localized, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "Localizable display name.", modularizeType: ColumnModularizeType.Property),
16 - new ColumnDefinition("RemoteAddresses", ColumnType.String, 0, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "Remote address to accept incoming connections from.", modularizeType: ColumnModularizeType.Property),
17 - new ColumnDefinition("Port", ColumnType.String, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, minValue: 1, description: "Port number.", modularizeType: ColumnModularizeType.Property),
18 - new ColumnDefinition("Protocol", ColumnType.Number, 1, primaryKey: false, nullable: true, ColumnCategory.Integer, minValue: 0, maxValue: 255, description: "Protocol (6=TCP; 17=UDP). https://www.iana.org/assignments/protocol-numbers"),
16 + new ColumnDefinition("RemoteAddresses", ColumnType.String, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "Remote address to accept incoming connections from.", modularizeType: ColumnModularizeType.Property),
17 + new ColumnDefinition("Port", ColumnType.String, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, minValue: 1, maxValue: 65535, description: "Local Port number.", modularizeType: ColumnModularizeType.Property),
18 + new ColumnDefinition("Protocol", ColumnType.String, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, minValue: 0, maxValue: 255, description: "Protocol (6=TCP; 17=UDP). https://www.iana.org/assignments/protocol-numbers", modularizeType: ColumnModularizeType.Property),
19 new ColumnDefinition("Program", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "Exception for a program (formatted path name).", modularizeType: ColumnModularizeType.Property),
20 - new ColumnDefinition("Attributes", ColumnType.Number, 4, primaryKey: false, nullable: true, ColumnCategory.Unknown, description: "Vital=1"),
21 - new ColumnDefinition("Profile", ColumnType.Number, 4, primaryKey: false, nullable: false, ColumnCategory.Integer, minValue: 1, maxValue: 2147483647, description: "Profile (1=domain; 2=private; 4=public; 2147483647=all)."),
20 + new ColumnDefinition("Attributes", ColumnType.Number, 4, primaryKey: false, nullable: true, ColumnCategory.Unknown, description: "Vital=1; IgnoreUpdates=2; EnableOnChange=4; INetFwRule2=8; INetFwRule3=16"),
21 + new ColumnDefinition("Profile", ColumnType.String, 4, primaryKey: false, nullable: true, ColumnCategory.Formatted, minValue: 1, maxValue: 2147483647, description: "Profile (1=domain; 2=private; 4=public; 2147483647=all).", modularizeType: ColumnModularizeType.Property),
22 new ColumnDefinition("Component_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, keyTable: "Component", keyColumn: 1, description: "Foreign key into the Component table referencing component that controls the firewall configuration.", modularizeType: ColumnModularizeType.Column),
23 new ColumnDefinition("Description", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "Description displayed in Windows Firewall manager for this firewall rule."),
24 - new ColumnDefinition("Direction", ColumnType.Number, 1, primaryKey: false, nullable: true, ColumnCategory.Integer, minValue: 1, maxValue: 2, description: "Direction (1=in; 2=out)"),
24 + new ColumnDefinition("Direction", ColumnType.Number, 1, primaryKey: false, nullable: false, ColumnCategory.Integer, minValue: 1, maxValue: 2, description: "Direction (1=in; 2=out)"),
25 + new ColumnDefinition("Action", ColumnType.String, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, minValue: 0, maxValue: 1, description: "Action (0=Block; 1=Allow).", modularizeType: ColumnModularizeType.Property),
26 + new ColumnDefinition("EdgeTraversal", ColumnType.String, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, minValue: 0, maxValue: 3, description: "Edge traversal (0=Deny; 1=Allow; 2=DeferToApp; 3=DeferToUser).", modularizeType: ColumnModularizeType.Property),
27 + new ColumnDefinition("Enabled", ColumnType.String, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, minValue: 0, maxValue: 1, description: "Enabled (0=Disabled; 1=Enabled).", modularizeType: ColumnModularizeType.Property),
28 + new ColumnDefinition("Grouping", ColumnType.String, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "The group to which the rule belongs.", modularizeType: ColumnModularizeType.Property),
29 + new ColumnDefinition("IcmpTypesAndCodes", ColumnType.String, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "Comma separated list of ICMP types and codes separated by colons.", modularizeType: ColumnModularizeType.Property),
30 + new ColumnDefinition("Interfaces", ColumnType.String, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "A list of network interfaces separated by a pipe character.", modularizeType: ColumnModularizeType.Property),
31 + new ColumnDefinition("InterfaceTypes", ColumnType.String, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "Comma separated list of interface types (combination of Wireless,Lan,RemoteAccess or All).", modularizeType: ColumnModularizeType.Property),
32 + new ColumnDefinition("LocalAddresses", ColumnType.String, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "Local address to accept incoming connections on.", modularizeType: ColumnModularizeType.Property),
33 + new ColumnDefinition("RemotePort", ColumnType.String, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, minValue: 1, maxValue: 65535, description: "Remote Port number.", modularizeType: ColumnModularizeType.Property),
34 + new ColumnDefinition("ServiceName", ColumnType.String, 256, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "Windows Service short name.", modularizeType: ColumnModularizeType.Property),
35 + new ColumnDefinition("LocalAppPackageId", ColumnType.String, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "Package identifier or the app container identifier of a process.", modularizeType: ColumnModularizeType.Property),
36 + new ColumnDefinition("LocalUserAuthorizedList", ColumnType.String, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "List of authorized local users for an app container.", modularizeType: ColumnModularizeType.Property),
37 + new ColumnDefinition("LocalUserOwner", ColumnType.String, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "SID of the user who is the owner of the rule.", modularizeType: ColumnModularizeType.Property),
38 + new ColumnDefinition("RemoteMachineAuthorizedList", ColumnType.String, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "List of remote computers which are authorized to access an app container.", modularizeType: ColumnModularizeType.Property),
39 + new ColumnDefinition("RemoteUserAuthorizedList", ColumnType.String, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "List of remote users who are authorized to access an app container.", modularizeType: ColumnModularizeType.Property),
40 + new ColumnDefinition("SecureFlags", ColumnType.String, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, minValue: 0, maxValue: 1, description: "NET_FW_AUTHENTICATE_TYPE IPsec verification level.", modularizeType: ColumnModularizeType.Property),
41 },
42 symbolIdIsPrimaryKey: true
43 );
src/ext/Firewall/wixext/Symbols/WixFirewallExceptionSymbol.cs
+135 -7
@@ -14,13 +14,29 @@ namespace WixToolset.Firewall
14 new IntermediateFieldDefinition(nameof(WixFirewallExceptionSymbolFields.Name), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(WixFirewallExceptionSymbolFields.RemoteAddresses), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(WixFirewallExceptionSymbolFields.Port), IntermediateFieldType.String),
17 - new IntermediateFieldDefinition(nameof(WixFirewallExceptionSymbolFields.Protocol), IntermediateFieldType.Number),
17 + new IntermediateFieldDefinition(nameof(WixFirewallExceptionSymbolFields.Protocol), IntermediateFieldType.String),
18 new IntermediateFieldDefinition(nameof(WixFirewallExceptionSymbolFields.Program), IntermediateFieldType.String),
19 new IntermediateFieldDefinition(nameof(WixFirewallExceptionSymbolFields.Attributes), IntermediateFieldType.Number),
20 - new IntermediateFieldDefinition(nameof(WixFirewallExceptionSymbolFields.Profile), IntermediateFieldType.Number),
20 + new IntermediateFieldDefinition(nameof(WixFirewallExceptionSymbolFields.Profile), IntermediateFieldType.String),
21 new IntermediateFieldDefinition(nameof(WixFirewallExceptionSymbolFields.ComponentRef), IntermediateFieldType.String),
22 new IntermediateFieldDefinition(nameof(WixFirewallExceptionSymbolFields.Description), IntermediateFieldType.String),
23 new IntermediateFieldDefinition(nameof(WixFirewallExceptionSymbolFields.Direction), IntermediateFieldType.Number),
24 + new IntermediateFieldDefinition(nameof(WixFirewallExceptionSymbolFields.Action), IntermediateFieldType.String),
25 + new IntermediateFieldDefinition(nameof(WixFirewallExceptionSymbolFields.EdgeTraversal), IntermediateFieldType.String),
26 + new IntermediateFieldDefinition(nameof(WixFirewallExceptionSymbolFields.Enabled), IntermediateFieldType.String),
27 + new IntermediateFieldDefinition(nameof(WixFirewallExceptionSymbolFields.Grouping), IntermediateFieldType.String),
28 + new IntermediateFieldDefinition(nameof(WixFirewallExceptionSymbolFields.IcmpTypesAndCodes), IntermediateFieldType.String),
29 + new IntermediateFieldDefinition(nameof(WixFirewallExceptionSymbolFields.Interfaces), IntermediateFieldType.String),
30 + new IntermediateFieldDefinition(nameof(WixFirewallExceptionSymbolFields.InterfaceTypes), IntermediateFieldType.String),
31 + new IntermediateFieldDefinition(nameof(WixFirewallExceptionSymbolFields.LocalAddresses), IntermediateFieldType.String),
32 + new IntermediateFieldDefinition(nameof(WixFirewallExceptionSymbolFields.RemotePort), IntermediateFieldType.String),
33 + new IntermediateFieldDefinition(nameof(WixFirewallExceptionSymbolFields.ServiceName), IntermediateFieldType.String),
34 + new IntermediateFieldDefinition(nameof(WixFirewallExceptionSymbolFields.LocalAppPackageId), IntermediateFieldType.String),
35 + new IntermediateFieldDefinition(nameof(WixFirewallExceptionSymbolFields.LocalUserAuthorizedList), IntermediateFieldType.String),
36 + new IntermediateFieldDefinition(nameof(WixFirewallExceptionSymbolFields.LocalUserOwner), IntermediateFieldType.String),
37 + new IntermediateFieldDefinition(nameof(WixFirewallExceptionSymbolFields.RemoteMachineAuthorizedList), IntermediateFieldType.String),
38 + new IntermediateFieldDefinition(nameof(WixFirewallExceptionSymbolFields.RemoteUserAuthorizedList), IntermediateFieldType.String),
39 + new IntermediateFieldDefinition(nameof(WixFirewallExceptionSymbolFields.SecureFlags), IntermediateFieldType.String),
40 },
41 typeof(WixFirewallExceptionSymbol));
42 }
@@ -42,6 +58,22 @@ namespace WixToolset.Firewall.Symbols
58 ComponentRef,
59 Description,
60 Direction,
61 + Action,
62 + EdgeTraversal,
63 + Enabled,
64 + Grouping,
65 + IcmpTypesAndCodes,
66 + Interfaces,
67 + InterfaceTypes,
68 + LocalAddresses,
69 + RemotePort,
70 + ServiceName,
71 + LocalAppPackageId,
72 + LocalUserAuthorizedList,
73 + LocalUserOwner,
74 + RemoteMachineAuthorizedList,
75 + RemoteUserAuthorizedList,
76 + SecureFlags,
77 }
78
79 public class WixFirewallExceptionSymbol : IntermediateSymbol
@@ -74,9 +106,9 @@ namespace WixToolset.Firewall.Symbols
106 set => this.Set((int)WixFirewallExceptionSymbolFields.Port, value);
107 }
108
77 - public int? Protocol
109 + public string Protocol
110 {
79 - get => this.Fields[(int)WixFirewallExceptionSymbolFields.Protocol].AsNullableNumber();
111 + get => this.Fields[(int)WixFirewallExceptionSymbolFields.Protocol].AsString();
112 set => this.Set((int)WixFirewallExceptionSymbolFields.Protocol, value);
113 }
114
@@ -92,9 +124,9 @@ namespace WixToolset.Firewall.Symbols
124 set => this.Set((int)WixFirewallExceptionSymbolFields.Attributes, value);
125 }
126
95 - public int Profile
127 + public string Profile
128 {
97 - get => this.Fields[(int)WixFirewallExceptionSymbolFields.Profile].AsNumber();
129 + get => this.Fields[(int)WixFirewallExceptionSymbolFields.Profile].AsString();
130 set => this.Set((int)WixFirewallExceptionSymbolFields.Profile, value);
131 }
132
@@ -115,5 +147,101 @@ namespace WixToolset.Firewall.Symbols
147 get => this.Fields[(int)WixFirewallExceptionSymbolFields.Direction].AsNumber();
148 set => this.Set((int)WixFirewallExceptionSymbolFields.Direction, value);
149 }
150 +
151 + public string Action
152 + {
153 + get => this.Fields[(int)WixFirewallExceptionSymbolFields.Action].AsString();
154 + set => this.Set((int)WixFirewallExceptionSymbolFields.Action, value);
155 + }
156 +
157 + public string EdgeTraversal
158 + {
159 + get => this.Fields[(int)WixFirewallExceptionSymbolFields.EdgeTraversal].AsString();
160 + set => this.Set((int)WixFirewallExceptionSymbolFields.EdgeTraversal, value);
161 + }
162 +
163 + public string Enabled
164 + {
165 + get => this.Fields[(int)WixFirewallExceptionSymbolFields.Enabled].AsString();
166 + set => this.Set((int)WixFirewallExceptionSymbolFields.Enabled, value);
167 + }
168 +
169 + public string Grouping
170 + {
171 + get => this.Fields[(int)WixFirewallExceptionSymbolFields.Grouping].AsString();
172 + set => this.Set((int)WixFirewallExceptionSymbolFields.Grouping, value);
173 + }
174 +
175 + public string IcmpTypesAndCodes
176 + {
177 + get => this.Fields[(int)WixFirewallExceptionSymbolFields.IcmpTypesAndCodes].AsString();
178 + set => this.Set((int)WixFirewallExceptionSymbolFields.IcmpTypesAndCodes, value);
179 + }
180 +
181 + public string Interfaces
182 + {
183 + get => this.Fields[(int)WixFirewallExceptionSymbolFields.Interfaces].AsString();
184 + set => this.Set((int)WixFirewallExceptionSymbolFields.Interfaces, value);
185 + }
186 +
187 + public string InterfaceTypes
188 + {
189 + get => this.Fields[(int)WixFirewallExceptionSymbolFields.InterfaceTypes].AsString();
190 + set => this.Set((int)WixFirewallExceptionSymbolFields.InterfaceTypes, value);
191 + }
192 +
193 + public string LocalAddresses
194 + {
195 + get => this.Fields[(int)WixFirewallExceptionSymbolFields.LocalAddresses].AsString();
196 + set => this.Set((int)WixFirewallExceptionSymbolFields.LocalAddresses, value);
197 + }
198 +
199 + public string RemotePort
200 + {
201 + get => this.Fields[(int)WixFirewallExceptionSymbolFields.RemotePort].AsString();
202 + set => this.Set((int)WixFirewallExceptionSymbolFields.RemotePort, value);
203 + }
204 +
205 + public string ServiceName
206 + {
207 + get => this.Fields[(int)WixFirewallExceptionSymbolFields.ServiceName].AsString();
208 + set => this.Set((int)WixFirewallExceptionSymbolFields.ServiceName, value);
209 + }
210 +
211 + public string LocalAppPackageId
212 + {
213 + get => this.Fields[(int)WixFirewallExceptionSymbolFields.LocalAppPackageId].AsString();
214 + set => this.Set((int)WixFirewallExceptionSymbolFields.LocalAppPackageId, value);
215 + }
216 +
217 + public string LocalUserAuthorizedList
218 + {
219 + get => this.Fields[(int)WixFirewallExceptionSymbolFields.LocalUserAuthorizedList].AsString();
220 + set => this.Set((int)WixFirewallExceptionSymbolFields.LocalUserAuthorizedList, value);
221 + }
222 +
223 + public string LocalUserOwner
224 + {
225 + get => this.Fields[(int)WixFirewallExceptionSymbolFields.LocalUserOwner].AsString();
226 + set => this.Set((int)WixFirewallExceptionSymbolFields.LocalUserOwner, value);
227 + }
228 +
229 + public string RemoteMachineAuthorizedList
230 + {
231 + get => this.Fields[(int)WixFirewallExceptionSymbolFields.RemoteMachineAuthorizedList].AsString();
232 + set => this.Set((int)WixFirewallExceptionSymbolFields.RemoteMachineAuthorizedList, value);
233 + }
234 +
235 + public string RemoteUserAuthorizedList
236 + {
237 + get => this.Fields[(int)WixFirewallExceptionSymbolFields.RemoteUserAuthorizedList].AsString();
238 + set => this.Set((int)WixFirewallExceptionSymbolFields.RemoteUserAuthorizedList, value);
239 + }
240 +
241 + public string SecureFlags
242 + {
243 + get => this.Fields[(int)WixFirewallExceptionSymbolFields.SecureFlags].AsString();
244 + set => this.Set((int)WixFirewallExceptionSymbolFields.SecureFlags, value);
245 + }
246 }
119 -}
\ No newline at end of file
247 +}
src/ext/Firewall/wixext/WixToolset.Firewall.wixext.csproj
+3 -1
@@ -5,9 +5,11 @@
5 <PropertyGroup>
6 <TargetFramework>netstandard2.0</TargetFramework>
7 <RootNamespace>WixToolset.Firewall</RootNamespace>
8 - <Description>WiX Toolset Firewallity Extension</Description>
8 + <Description>WiX Toolset Firewall Extension</Description>
9 <Title>WiX Toolset Firewall Extension</Title>
10 <DebugType>embedded</DebugType>
11 + <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
12 + <GenerateTargetFrameworkAttribute>false</GenerateTargetFrameworkAttribute>
13 </PropertyGroup>
14
15 <Import Project="..\..\WixExt.props" />
src/ext/Util/wixext/UtilCompiler.cs
+10 -3
@@ -3123,8 +3123,14 @@ namespace WixToolset.Util
3123 // if this element is a child of ServiceInstall then ignore the service name provided.
3124 if ("ServiceInstall" == parentTableName)
3125 {
3126 - // TODO: the ServiceName attribute should not be allowed in this case (the overwriting behavior may confuse users)
3127 - serviceName = parentTableServiceName;
3126 + if (null == serviceName || parentTableServiceName == serviceName)
3127 + {
3128 + serviceName = parentTableServiceName;
3129 + }
3130 + else
3131 + {
3132 + this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, "ServiceName", parentTableName));
3133 + }
3134 newService = true;
3135 }
3136 else
@@ -3136,7 +3142,8 @@ namespace WixToolset.Util
3142 }
3143 }
3144
3139 - this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
3145 + var context = new Dictionary<string, string>() { { "ServiceConfigComponentId", componentId }, { "ServiceConfigServiceName", serviceName } };
3146 + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element, context);
3147
3148 if (!this.Messaging.EncounteredError)
3149 {
src/internal/SetBuildNumber/Directory.Packages.props.pp
+1
@@ -47,6 +47,7 @@
47 <PackageVersion Include="System.DirectoryServices.AccountManagement" Version="4.7.0" />
48 <PackageVersion Include="System.IO.Compression" Version="4.3.0" />
49 <PackageVersion Include="System.IO.FileSystem.AccessControl" Version="4.7.0" />
50 + <PackageVersion Include="System.Net.NetworkInformation" Version="4.3.0" />
51 <PackageVersion Include="System.Reflection.Metadata" Version="1.6.0" />
52 <PackageVersion Include="System.Security.Principal.Windows" Version="4.7.0" />
53 <PackageVersion Include="System.Text.Encoding.CodePages" Version="4.7.0" />
src/test/burn/WixTestTools/Firewall/RuleDetails.cs
+5 -3
@@ -146,7 +146,9 @@ namespace WixTestTools.Firewall
146 /// This parameter allows the specification of an array of interface LUIDs (locally unique identifiers) supplied as strings.<br/>
147 /// This is commonly used by USB RNDIS (Remote Network Driver Interface Specification) devices to restrict traffic to a specific non-routable interface.<br/>
148 /// Use <b>netsh trace show interfaces</b> to show a list of local interfaces and their LUIDs.<br/>
149 - /// Example: new object[] { "Wi-Fi", "Local Area Connection* 14" }
149 + /// The interfaces are stored in the registry as GUIDs, but need to be passed to the API as text. eg from the registry<br/>
150 + /// v2.30|Action=Allow|Active=TRUE|Dir=In|Protocol=6|LPort=23456|IF={423411CD-E627-4A1A-9E1F-C5BE6CD2CC99}|IF={49A98AD0-8379-4079-A445-77066C52E338}|Name=WiXToolset401 Test - 0002|Desc=WiX Toolset firewall exception rule integration test - minimal port properties|<br/>
151 + /// Example API value: new object[] { "Wi-Fi", "Local Area Connection* 14" }
152 /// </summary>
153 public object[] Interfaces { get; set; }
154
@@ -227,13 +229,13 @@ namespace WixTestTools.Firewall
229 public string LocalUserOwner { get; set; }
230
231 /// <summary>
230 - /// This property is optional. It specifies a list of authorized local users for an app container.<br/>
232 + /// This property is optional. It specifies a list of authorized local users for an app container (using SDDL).<br/>
233 /// Example: "O:LSD:(A;;CC;;;S-1-5-84-0-0-0-0-0)"
234 /// </summary>
235 public string LocalUserAuthorizedList { get; set; }
236
237 /// <summary>
236 - /// This property is optional. It specifies a list of remote users who are authorized to access an app container.<br/>
238 + /// This property is optional. It specifies a list of remote users who are authorized to access an app container (using SDDL).<br/>
239 /// </summary>
240 public string RemoteUserAuthorizedList { get; set; }
241
src/test/msi/TestData/FirewallExtensionTests/CrossVersionMerge/CrossVersionMerge.wixproj new
+13
@@ -0,0 +1,13 @@
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 +<Project Sdk="WixToolset.Sdk">
3 + <PropertyGroup>
4 + <SuppressSpecificWarnings>1055;1056</SuppressSpecificWarnings>
5 + </PropertyGroup>
6 + <ItemGroup>
7 + <!-- <ProjectReference Include="..\Module401\Module401.wixproj" /> -->
8 + <ProjectReference Include="..\ModuleCurrent\ModuleCurrent.wixproj" />
9 + </ItemGroup>
10 + <ItemGroup>
11 + <PackageReference Include="WixToolset.Firewall.wixext" />
12 + </ItemGroup>
13 +</Project>
src/test/msi/TestData/FirewallExtensionTests/CrossVersionMerge/Module401.msm
Binary files /dev/null and b/src/test/msi/TestData/FirewallExtensionTests/CrossVersionMerge/Module401.msm differ
src/test/msi/TestData/FirewallExtensionTests/CrossVersionMerge/package.wxs new
+35
@@ -0,0 +1,35 @@
1 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:fw="http://wixtoolset.org/schemas/v4/wxs/firewall">
2 + <Package Name="MsiPackage" Language="1033" Version="1.0.0.0" Manufacturer="Example Corporation"
3 + UpgradeCode="41B5F815-E7F6-44E0-B92A-AE95DFF683F9" Compressed="yes" Scope="perMachine">
4 + <MediaTemplate EmbedCab="yes" />
5 +
6 + <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
7 +
8 + <Feature Id="ProductFeature" Title="Feature with merged modules">
9 + <MergeRef Id="TestMsm1" />
10 + <MergeRef Id="TestMsm2" />
11 + <ComponentRef Id="FirewallComponent1" />
12 + </Feature>
13 + </Package>
14 +
15 + <Fragment>
16 + <StandardDirectory Id="ProgramFilesFolder">
17 + <Directory Id="INSTALLFOLDER" Name="MsiPackage">
18 + <Merge Id="TestMsm1" Language="1033" SourceFile="Module401.msm" />
19 + <Merge Id="TestMsm2" Language="1033" SourceFile="ModuleCurrent.msm" />
20 + </Directory>
21 + </StandardDirectory>
22 + </Fragment>
23 +
24 + <Fragment>
25 + <Property Id="MSIPORT1" Value="20001" />
26 + <Property Id="MSIPORT2" Value="20002" />
27 +
28 + <Component Id="FirewallComponent1" Guid="3E9A6190-3E6B-4BC2-8C84-D89D1549FEBD" Directory="INSTALLFOLDER">
29 + <File Source="$(sys.SOURCEFILEPATH)">
30 + <fw:FirewallException Id="FirewallException1" Description="WiX Toolset firewall exception rule integration test - package app" Name="WiXToolset Test - 0026" Scope="any" Port="[MSIPORT1]" />
31 + </File>
32 + <fw:FirewallException Id="FirewallException2" Description="WiX Toolset firewall exception rule integration test - package port" Name="WiXToolset Test - 0027" Scope="any" Port="[MSIPORT2]" />
33 + </Component>
34 + </Fragment>
35 +</Wix>
src/test/msi/TestData/FirewallExtensionTests/FirewallRulesInterfaces/FirewallRulesInterfaces.wixproj new
+13
@@ -0,0 +1,13 @@
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 +<Project Sdk="WixToolset.Sdk">
3 + <PropertyGroup>
4 + <UpgradeCode>{F153C27F-0236-4A0F-ADB3-50BFC73B4FEA}</UpgradeCode>
5 + <ProductComponentsRef>true</ProductComponentsRef>
6 + </PropertyGroup>
7 + <ItemGroup>
8 + <Compile Include="..\..\Templates\Product.wxs" Link="Product.wxs" />
9 + </ItemGroup>
10 + <ItemGroup>
11 + <PackageReference Include="WixToolset.Firewall.wixext" />
12 + </ItemGroup>
13 +</Project>
\ No newline at end of file
src/test/msi/TestData/FirewallExtensionTests/FirewallRulesInterfaces/product.wxs new
+32
@@ -0,0 +1,32 @@
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 +
4 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:fw="http://wixtoolset.org/schemas/v4/wxs/firewall">
5 + <Fragment>
6 + <ComponentGroup Id="ProductComponents">
7 + <ComponentRef Id="FirewallComponent1"/>
8 + </ComponentGroup>
9 + </Fragment>
10 +
11 + <Fragment>
12 + <Component Id="FirewallComponent1" Guid="08044660-CB5D-4891-8BD5-0CB5BB668D78" Directory="INSTALLFOLDER">
13 + <File Source="$(sys.SOURCEFILEPATH)" KeyPath="yes" >
14 + <fw:FirewallException Id="FirewallException28"
15 + Description="WiX Toolset firewall exception rule integration test - three interfaces"
16 + Name="WiXToolset500 Test - 0028" Scope="any" >
17 + <fw:Interface Name="[INTERFACE1]" />
18 + <fw:Interface Name="[INTERFACE2]" />
19 + <fw:Interface Name="[INTERFACE3]" />
20 + <fw:InterfaceType Value="RemoteAccess" />
21 + <fw:InterfaceType Value="Lan" />
22 + <fw:InterfaceType Value="Wireless" />
23 + </fw:FirewallException>
24 + </File>
25 +
26 + <fw:FirewallException Id="FirewallException29"
27 + Description="WiX Toolset firewall exception rule integration test - one interface"
28 + Name="WiXToolset500 Test - 0029" Scope="any" Port="29292" Interface="[INTERFACE1]" InterfaceType="[INTERFACETYPE]" >
29 + </fw:FirewallException>
30 + </Component>
31 + </Fragment>
32 +</Wix>
src/test/msi/TestData/FirewallExtensionTests/FirewallRulesProperties/FirewallRulesProperties.wixproj new
+13
@@ -0,0 +1,13 @@
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 +<Project Sdk="WixToolset.Sdk">
3 + <PropertyGroup>
4 + <UpgradeCode>{DC2C3CDC-112F-40A8-A7B4-2C7B758F4F94}</UpgradeCode>
5 + <ProductComponentsRef>true</ProductComponentsRef>
6 + </PropertyGroup>
7 + <ItemGroup>
8 + <Compile Include="..\..\Templates\Product.wxs" Link="Product.wxs" />
9 + </ItemGroup>
10 + <ItemGroup>
11 + <PackageReference Include="WixToolset.Firewall.wixext" />
12 + </ItemGroup>
13 +</Project>
\ No newline at end of file
src/test/msi/TestData/FirewallExtensionTests/FirewallRulesProperties/product.wxs new
+57
@@ -0,0 +1,57 @@
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 +
4 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:fw="http://wixtoolset.org/schemas/v4/wxs/firewall">
5 + <Fragment>
6 + <ComponentGroup Id="ProductComponents">
7 + <ComponentRef Id="FirewallComponent1"/>
8 + </ComponentGroup>
9 + </Fragment>
10 +
11 + <Fragment>
12 + <Component Id="FirewallComponent1" Guid="A1553D10-BEB7-4E60-A0DC-6F1EEE5A1719" Directory="INSTALLFOLDER">
13 + <fw:FirewallException
14 + Name="WiXToolset Test - 0028" OnUpdate="EnableOnly"
15 + Port="[LOCALPORT]"
16 + Protocol="[PROTOCOL]"
17 + Program="[PROGRAM]"
18 + Profile="[PROFILE]"
19 + Description="[DESCRIPTION]"
20 + Scope="[REMOTESCOPE]"
21 + EdgeTraversal="[EDGETRAVERSAL]"
22 + Enabled="[ENABLED]"
23 + Grouping="[GROUPING]"
24 + IcmpTypesAndCodes="[ICMPTYPES]"
25 + Interface="[INTERFACE]"
26 + InterfaceType="[INTERFACETYPE]"
27 + LocalScope="[LOCALSCOPE]"
28 + RemotePort="[REMOTEPORT]"
29 + Service="[SERVICE]"
30 + LocalAppPackageId="[PACKAGEID]"
31 + LocalUserAuthorizedList="[LOCALUSERS]"
32 + LocalUserOwner="[LOCALOWNER]"
33 + RemoteMachineAuthorizedList="[REMOTEMACHINES]"
34 + RemoteUserAuthorizedList="[REMOTEUSERS]"
35 + IPSecSecureFlags="[SECUREFLAGS]"
36 + />
37 +
38 + <fw:FirewallException Name="WiXToolset Test - 0029" OnUpdate="DoNothing" >
39 + <fw:RemoteAddress Value="[REMOTEADDRESS]" />
40 + <fw:LocalAddress Value="[LOCALADDRESS]" />
41 + <fw:InterfaceType Value="[INTERFACETYPE]" />
42 + <fw:Interface Name="[INTERFACE]" />
43 + </fw:FirewallException>
44 +
45 + <fw:FirewallException Name="WiXToolset Test - 0030" >
46 + <fw:RemoteAddress Value="[REMOTEADDRESS1]" />
47 + <fw:RemoteAddress Value="[REMOTEADDRESS2]" />
48 + <fw:LocalAddress Value="[LOCALADDRESS1]" />
49 + <fw:LocalAddress Value="[LOCALADDRESS2]" />
50 + <fw:InterfaceType Value="[INTERFACETYPE1]" />
51 + <fw:InterfaceType Value="[INTERFACETYPE2]" />
52 + <fw:Interface Name="[INTERFACE1]" />
53 + <fw:Interface Name="[INTERFACE2]" />
54 + </fw:FirewallException>
55 + </Component>
56 + </Fragment>
57 +</Wix>
src/test/msi/TestData/FirewallExtensionTests/Module401/Module401.wixproj new
+10
@@ -0,0 +1,10 @@
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 +<Project Sdk="WixToolset.Sdk">
3 + <PropertyGroup>
4 + <OutputType>Module</OutputType>
5 + <SuppressSpecificWarnings>1072</SuppressSpecificWarnings>
6 + </PropertyGroup>
7 + <ItemGroup>
8 + <PackageReference Include="WixToolset.Firewall.wixext"/><!--VersionOverride="4.0.1"-->
9 + </ItemGroup>
10 +</Project>
\ No newline at end of file
src/test/msi/TestData/FirewallExtensionTests/Module401/data/test.txt new
+1
@@ -0,0 +1 @@
1 +This is test.txt.
\ No newline at end of file
src/test/msi/TestData/FirewallExtensionTests/Module401/module.wxs new
+36
@@ -0,0 +1,36 @@
1 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:fw="http://wixtoolset.org/schemas/v4/wxs/firewall" >
2 + <Module Id="MergeModule1" Language="1033" Version="1.0.0.0" Guid="4B2C61BF-59F5-453B-98E3-3389F681EA00">
3 + <SummaryInformation Manufacturer="Module 4.0.1 Manufacturer" />
4 +
5 + <Property Id="MODULE401PORT1" Value="40101" />
6 + <Property Id="MODULE401PORT2" Value="40102" />
7 + <Property Id="MODULE401PORT3" Value="40103" />
8 + <Property Id="MODULE401PORT4" Value="40104" />
9 +
10 + <Directory Id="MergeRedirectFolder">
11 + <Component Id="ModuleComponent1" Guid="257F9283-1334-423C-A7E7-FEE848BCD37F">
12 + <File Id="File1" Name="file1.txt" Source="data/test.txt">
13 + <fw:FirewallException Id="FirewallException1"
14 + Description="WiX Toolset firewall exception rule integration test - module 401 MergeRedirectFolder - app"
15 + Name="WiXToolset401 Test - 0018" Scope="any" Port="[MODULE401PORT1]" />
16 + </File>
17 + <fw:FirewallException Id="FirewallException2"
18 + Description="WiX Toolset firewall exception rule integration test - module 401 MergeRedirectFolder - port"
19 + Name="WiXToolset401 Test - 0019" Scope="any" Port="[MODULE401PORT2]" />
20 + </Component>
21 + </Directory>
22 +
23 + <Directory Id="NotTheMergeRedirectFolder">
24 + <Component Id="ModuleComponent2" Guid="48A2D573-0ADB-4010-84E3-96C3D6803E90">
25 + <File Id="File2" Name="file2.txt" Source="data/test.txt">
26 + <fw:FirewallException Id="FirewallException3"
27 + Description="WiX Toolset firewall exception rule integration test - module 401 NotTheMergeRedirectFolder - app"
28 + Name="WiXToolset401 Test - 0020" Scope="any" Port="[MODULE401PORT3]" />
29 + </File>
30 + <fw:FirewallException Id="FirewallException4"
31 + Description="WiX Toolset firewall exception rule integration test - module 401 NotTheMergeRedirectFolder - port"
32 + Name="WiXToolset401 Test - 0021" Scope="any" Port="[MODULE401PORT4]" />
33 + </Component>
34 + </Directory>
35 + </Module>
36 +</Wix>
src/test/msi/TestData/FirewallExtensionTests/ModuleCurrent/ModuleCurrent.wixproj new
+10
@@ -0,0 +1,10 @@
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 +<Project Sdk="WixToolset.Sdk">
3 + <PropertyGroup>
4 + <OutputType>Module</OutputType>
5 + <SuppressSpecificWarnings>1072</SuppressSpecificWarnings>
6 + </PropertyGroup>
7 + <ItemGroup>
8 + <PackageReference Include="WixToolset.Firewall.wixext" />
9 + </ItemGroup>
10 +</Project>
\ No newline at end of file
src/test/msi/TestData/FirewallExtensionTests/ModuleCurrent/data/test.txt new
+1
@@ -0,0 +1 @@
1 +This is test.txt.
\ No newline at end of file
src/test/msi/TestData/FirewallExtensionTests/ModuleCurrent/module.wxs new
+36
@@ -0,0 +1,36 @@
1 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:fw="http://wixtoolset.org/schemas/v4/wxs/firewall" >
2 + <Module Id="MergeModule1" Language="1033" Version="1.0.0.0" Guid="44FA5DBE-2413-436E-99B3-A0751D6EB420">
3 + <SummaryInformation Manufacturer="Example Company - Module Current" />
4 +
5 + <Property Id="MODULECURRENTPORT1" Value="50001" />
6 + <Property Id="MODULECURRENTPORT2" Value="50002" />
7 + <Property Id="MODULECURRENTPORT3" Value="50003" />
8 + <Property Id="MODULECURRENTPORT4" Value="50004" />
9 +
10 + <Directory Id="MergeRedirectFolder">
11 + <Component Id="ModuleComponent1" Guid="EB7B8A63-85C4-4ABB-B9DA-33AECAFE38F7">
12 + <File Id="File1" Name="file1.txt" Source="data/test.txt">
13 + <fw:FirewallException Id="FirewallException1"
14 + Description="WiX Toolset firewall exception rule integration test - module MergeRedirectFolder - app"
15 + Name="WiXToolset Test - 0022" Scope="any" Port="[MODULECURRENTPORT1]" />
16 + </File>
17 + <fw:FirewallException Id="FirewallException2"
18 + Description="WiX Toolset firewall exception rule integration test - module MergeRedirectFolder - port"
19 + Name="WiXToolset Test - 0023" Scope="any" Port="[MODULECURRENTPORT2]" />
20 + </Component>
21 + </Directory>
22 +
23 + <Directory Id="NotTheMergeRedirectFolder">
24 + <Component Id="ModuleComponent2" Guid="0C9DD4FC-5A54-4E96-830D-DDE27B3017B5">
25 + <File Id="File2" Name="file2.txt" Source="data/test.txt">
26 + <fw:FirewallException Id="FirewallException3"
27 + Description="WiX Toolset firewall exception rule integration test - module NotTheMergeRedirectFolder - app"
28 + Name="WiXToolset Test - 0024" Scope="any" Port="[MODULECURRENTPORT3]" />
29 + </File>
30 + <fw:FirewallException Id="FirewallException4"
31 + Description="WiX Toolset firewall exception rule integration test - module NotTheMergeRedirectFolder - port"
32 + Name="WiXToolset Test - 0025" Scope="any" Port="[MODULECURRENTPORT4]" />
33 + </Component>
34 + </Directory>
35 + </Module>
36 +</Wix>
src/test/msi/TestData/FirewallExtensionTests/NestedService/NestedService.wixproj new
+14
@@ -0,0 +1,14 @@
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 +<Project Sdk="WixToolset.Sdk">
3 + <PropertyGroup>
4 + <UpgradeCode>{80635798-F904-4C4E-81D8-27A5106F3998}</UpgradeCode>
5 + <ProductComponentsRef>true</ProductComponentsRef>
6 + </PropertyGroup>
7 + <ItemGroup>
8 + <Compile Include="..\..\Templates\Product.wxs" Link="Product.wxs" />
9 + </ItemGroup>
10 + <ItemGroup>
11 + <PackageReference Include="WixToolset.Firewall.wixext" />
12 + <PackageReference Include="WixToolset.Util.wixext" />
13 + </ItemGroup>
14 +</Project>
\ No newline at end of file
src/test/msi/TestData/FirewallExtensionTests/NestedService/product.wxs new
+25
@@ -0,0 +1,25 @@
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 +
4 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:fw="http://wixtoolset.org/schemas/v4/wxs/firewall" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util" >
5 + <Fragment>
6 + <ComponentGroup Id="ProductComponents">
7 + <ComponentRef Id="FirewallComponent1"/>
8 + </ComponentGroup>
9 + </Fragment>
10 +
11 + <Fragment>
12 + <Component Id="FirewallComponent1" Guid="FD6E696A-8C42-49BF-B686-0DA5CD4B2C5A" Directory="INSTALLFOLDER" >
13 + <fw:FirewallException Id="FirewallException1" Description="WiX Toolset firewall exception rule integration test - service property"
14 + Name="WiXToolset Test - 0031" Service="Spooler"/>
15 + <util:ServiceConfig ServiceName="Spooler" FirstFailureActionType="restart" SecondFailureActionType="restart" ThirdFailureActionType="none" >
16 + <fw:FirewallException Id="FirewallException2" Description="WiX Toolset firewall exception rule integration test - ServiceConfig"
17 + Name="WiXToolset Test - 0032" />
18 + </util:ServiceConfig>
19 + <ServiceInstall Name="WixTestFirewallSrv" Type="ownProcess" Start="disabled" ErrorControl="ignore" Vital="no" Arguments="%WINDIR%\System32\spoolsv.exe" >
20 + <fw:FirewallException Id="FirewallException3" Description="WiX Toolset firewall exception rule integration test - ServiceInstall"
21 + Name="WiXToolset Test - 0033" />
22 + </ServiceInstall>
23 + </Component>
24 + </Fragment>
25 +</Wix>
src/test/msi/WixToolsetTest.MsiE2E/FirewallExtensionTests.cs
+623 -17
@@ -4,6 +4,8 @@ namespace WixToolsetTest.MsiE2E
4 {
5 using System;
6 using System.IO;
7 + using System.Linq;
8 + using System.Net.NetworkInformation;
9 using NetFwTypeLib;
10 using WixTestTools;
11 using WixTestTools.Firewall;
@@ -37,8 +39,8 @@ namespace WixToolsetTest.MsiE2E
39 ApplicationName = this.TestContext.GetTestInstallFolder(false, Path.Combine("FirewallRules", "product.wxs")),
40 Description = "WiX Toolset firewall exception rule integration test - minimal app properties",
41 Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN,
40 - EdgeTraversal = true,
41 - EdgeTraversalOptions = 1,
42 + EdgeTraversal = false,
43 + EdgeTraversalOptions = 0,
44 Enabled = true,
45 InterfaceTypes = "All",
46 LocalAddresses = "*",
@@ -124,8 +126,8 @@ namespace WixToolsetTest.MsiE2E
126 ApplicationName = this.TestContext.GetTestInstallFolder(false, Path.Combine("FirewallRules", "product.wxs")),
127 Description = "WiX Toolset firewall exception rule integration test - minimal app properties",
128 Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN,
127 - EdgeTraversal = true,
128 - EdgeTraversalOptions = 1,
129 + EdgeTraversal = false,
130 + EdgeTraversalOptions = 0,
131 Enabled = true,
132 InterfaceTypes = "All",
133 LocalAddresses = "*",
@@ -187,8 +189,8 @@ namespace WixToolsetTest.MsiE2E
189 ApplicationName = this.TestContext.GetTestInstallFolder(false, Path.Combine("FirewallRules", "product.wxs")),
190 Description = "WiX Toolset firewall exception rule integration test - minimal app properties",
191 Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN,
190 - EdgeTraversal = true,
191 - EdgeTraversalOptions = 1,
192 + EdgeTraversal = false,
193 + EdgeTraversalOptions = 0,
194 Enabled = true,
195 InterfaceTypes = "All",
196 LocalAddresses = "*",
@@ -213,8 +215,8 @@ namespace WixToolsetTest.MsiE2E
215 ApplicationName = this.TestContext.GetTestInstallFolder(false, Path.Combine("DynamicFirewallRules", "product.wxs")),
216 Description = "WiX Toolset firewall exception rule integration test - dynamic app description 9999",
217 Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN,
216 - EdgeTraversal = true,
217 - EdgeTraversalOptions = 1,
218 + EdgeTraversal = false,
219 + EdgeTraversalOptions = 0,
220 Enabled = true,
221 InterfaceTypes = "All",
222 LocalAddresses = "*",
@@ -255,8 +257,8 @@ namespace WixToolsetTest.MsiE2E
257 ApplicationName = Path.Combine(Environment.GetEnvironmentVariable("windir"), "system32", "9999.exe"),
258 Description = "WiX Toolset firewall exception rule integration test - dynamic Name 9999",
259 Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN,
258 - EdgeTraversal = true,
259 - EdgeTraversalOptions = 1,
260 + EdgeTraversal = false,
261 + EdgeTraversalOptions = 0,
262 Enabled = true,
263 InterfaceTypes = "All",
264 LocalAddresses = "*",
@@ -285,10 +287,10 @@ namespace WixToolsetTest.MsiE2E
287 var log1 = product.InstallProduct(MSIExec.MSIExecReturnCode.SUCCESS);
288
289 Assert.False(Verifier.FirewallRuleExists("WiXToolset401 Test - 0006 pipe"));
288 - Assert.True(LogVerifier.MessageInLogFile(log1, "failed to add app to the authorized apps list"));
290 + Assert.True(LogVerifier.MessageInLogFile(log1, "failed to add firewall exception 'WiXToolset401 Test - 0006 pipe' to the list"));
291
292 Assert.False(Verifier.FirewallRuleExists("WiXToolset401 Test - 0007 pipe"));
291 - Assert.True(LogVerifier.MessageInLogFile(log1, "failed to add app to the authorized ports list"));
293 + Assert.True(LogVerifier.MessageInLogFile(log1, "failed to add firewall exception 'WiXToolset401 Test - 0007 pipe' to the list"));
294
295 var expected = new RuleDetails("WiXToolset401 Test - 0008 removal")
296 {
@@ -296,8 +298,8 @@ namespace WixToolsetTest.MsiE2E
298 ApplicationName = "test.exe",
299 Description = "WiX Toolset firewall exception rule integration test - removal test",
300 Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN,
299 - EdgeTraversal = true,
300 - EdgeTraversalOptions = 1,
301 + EdgeTraversal = false,
302 + EdgeTraversalOptions = 0,
303 Enabled = true,
304 InterfaceTypes = "All",
305 LocalPorts = "52390",
@@ -313,7 +315,7 @@ namespace WixToolsetTest.MsiE2E
315 Verifier.RemoveFirewallRuleByName("WiXToolset401 Test - 0008 removal");
316
317 var log2 = product.UninstallProduct(MSIExec.MSIExecReturnCode.SUCCESS, "NORULENAME=1");
316 - Assert.True(LogVerifier.MessageInLogFile(log2, "failed to remove firewall rule"));
318 + Assert.True(LogVerifier.MessageInLogFile(log2, "failed to remove firewall exception for name"));
319 }
320
321 [RuntimeFact]
@@ -370,8 +372,8 @@ namespace WixToolsetTest.MsiE2E
372 ApplicationName = "test.exe",
373 Description = "WiX Toolset firewall exception rule integration test - ports can only be specified if protocol is TCP or UDP",
374 Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN,
373 - EdgeTraversal = true,
374 - EdgeTraversalOptions = 1,
375 + EdgeTraversal = false,
376 + EdgeTraversalOptions = 0,
377 Enabled = true,
378 InterfaceTypes = "All",
379 LocalAddresses = "*",
@@ -532,5 +534,609 @@ namespace WixToolsetTest.MsiE2E
534 Assert.False(Verifier.FirewallRuleExists("WiXToolset401 Test - 0016"));
535 Assert.False(Verifier.FirewallRuleExists("WiXToolset401 Test - 0017"));
536 }
537 +
538 + [RuntimeFact]
539 + public void CanInstallAndUninstallFirewallRulesWithInterfaces()
540 + {
541 + var names = NetworkInterface.GetAllNetworkInterfaces()
542 + .Take(3)
543 + .Select(ni => ni.Name);
544 +
545 + var props = names.Select((name, idx) => $"INTERFACE{idx + 1}=\"{name}\"")
546 + .Concat(new[] { "INTERFACETYPE=Lan" }).ToArray();
547 +
548 + var product = this.CreatePackageInstaller("FirewallRulesInterfaces");
549 + product.InstallProduct(MSIExec.MSIExecReturnCode.SUCCESS, props);
550 +
551 + var expected1 = new RuleDetails("WiXToolset500 Test - 0028")
552 + {
553 + Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW,
554 + ApplicationName = this.TestContext.GetTestInstallFolder(false, Path.Combine("FirewallRulesInterfaces", "product.wxs")),
555 + Description = "WiX Toolset firewall exception rule integration test - three interfaces",
556 + Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN,
557 + EdgeTraversal = false,
558 + EdgeTraversalOptions = 0,
559 + Enabled = true,
560 + InterfaceTypes = "Lan,Wireless,RemoteAccess",
561 + Interfaces = names.ToArray<object>(),
562 + LocalAddresses = "*",
563 + Profiles = Int32.MaxValue,
564 + Protocol = 256,
565 + RemoteAddresses = "*",
566 + SecureFlags = 0,
567 + };
568 +
569 + Verifier.VerifyFirewallRule("WiXToolset500 Test - 0028", expected1);
570 +
571 + var expected2 = new RuleDetails("WiXToolset500 Test - 0029")
572 + {
573 + Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW,
574 + Description = "WiX Toolset firewall exception rule integration test - one interface",
575 + Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN,
576 + EdgeTraversal = false,
577 + EdgeTraversalOptions = 0,
578 + Enabled = true,
579 + InterfaceTypes = "Lan",
580 + Interfaces = names.Take(1).ToArray<object>(),
581 + LocalAddresses = "*",
582 + LocalPorts = "29292",
583 + Profiles = Int32.MaxValue,
584 + Protocol = 6,
585 + RemoteAddresses = "*",
586 + RemotePorts = "*",
587 + SecureFlags = 0,
588 + };
589 +
590 + Verifier.VerifyFirewallRule("WiXToolset500 Test - 0029", expected2);
591 +
592 + props = names.Take(1).Select((name, idx) => $"INTERFACE{idx + 2}=\"{name}\"").ToArray();
593 +
594 + product.RepairProduct(MSIExec.MSIExecReturnCode.SUCCESS, props);
595 +
596 + var expected3 = new RuleDetails("WiXToolset500 Test - 0028")
597 + {
598 + Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW,
599 + ApplicationName = this.TestContext.GetTestInstallFolder(false, Path.Combine("FirewallRulesInterfaces", "product.wxs")),
600 + Description = "WiX Toolset firewall exception rule integration test - three interfaces",
601 + Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN,
602 + EdgeTraversal = false,
603 + EdgeTraversalOptions = 0,
604 + Enabled = true,
605 + InterfaceTypes = "Lan,Wireless,RemoteAccess",
606 + Interfaces = names.Take(1).ToArray<object>(),
607 + LocalAddresses = "*",
608 + Profiles = Int32.MaxValue,
609 + Protocol = 256,
610 + RemoteAddresses = "*",
611 + SecureFlags = 0,
612 + };
613 +
614 + Verifier.VerifyFirewallRule("WiXToolset500 Test - 0028", expected3);
615 +
616 + var expected4 = new RuleDetails("WiXToolset500 Test - 0029")
617 + {
618 + Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW,
619 + Description = "WiX Toolset firewall exception rule integration test - one interface",
620 + Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN,
621 + EdgeTraversal = false,
622 + EdgeTraversalOptions = 0,
623 + Enabled = true,
624 + InterfaceTypes = "All",
625 + LocalAddresses = "*",
626 + LocalPorts = "29292",
627 + Profiles = Int32.MaxValue,
628 + Protocol = 6,
629 + RemoteAddresses = "*",
630 + RemotePorts = "*",
631 + SecureFlags = 0,
632 + };
633 +
634 + Verifier.VerifyFirewallRule("WiXToolset500 Test - 0029", expected4);
635 +
636 + product.UninstallProduct(MSIExec.MSIExecReturnCode.SUCCESS);
637 +
638 + // verify the firewall exceptions have been removed.
639 + Assert.False(Verifier.FirewallRuleExists("WiXToolset500 Test - 0028"));
640 + Assert.False(Verifier.FirewallRuleExists("WiXToolset500 Test - 0029"));
641 + }
642 +
643 + [RuntimeFact]
644 + public void CanInstallAndUninstallFirewallRulesPackagedByDifferentModules()
645 + {
646 + var product = this.CreatePackageInstaller("CrossVersionMerge");
647 + product.InstallProduct(MSIExec.MSIExecReturnCode.SUCCESS);
648 +
649 + // Validate new firewall exception details.
650 + var expected1 = new RuleDetails("WiXToolset401 Test - 0018")
651 + {
652 + Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW,
653 + ApplicationName = Path.Combine(Environment.GetEnvironmentVariable("ProgramFiles(x86)"), "MsiPackage", "file1.txt"),
654 + Description = "WiX Toolset firewall exception rule integration test - module 401 MergeRedirectFolder - app",
655 + Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN,
656 + EdgeTraversal = true,
657 + EdgeTraversalOptions = 1,
658 + Enabled = true,
659 + InterfaceTypes = "All",
660 + LocalAddresses = "*",
661 + LocalPorts = "40101",
662 + Profiles = Int32.MaxValue,
663 + Protocol = 6,
664 + RemoteAddresses = "*",
665 + RemotePorts = "*",
666 + SecureFlags = 0,
667 + };
668 +
669 + Verifier.VerifyFirewallRule("WiXToolset401 Test - 0018", expected1);
670 +
671 + var expected2 = new RuleDetails("WiXToolset401 Test - 0019")
672 + {
673 + Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW,
674 + Description = "WiX Toolset firewall exception rule integration test - module 401 MergeRedirectFolder - port",
675 + Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN,
676 + EdgeTraversal = false,
677 + EdgeTraversalOptions = 0,
678 + Enabled = true,
679 + InterfaceTypes = "All",
680 + LocalAddresses = "*",
681 + LocalPorts = "40102",
682 + Profiles = Int32.MaxValue,
683 + Protocol = 6,
684 + RemoteAddresses = "*",
685 + RemotePorts = "*",
686 + SecureFlags = 0,
687 + };
688 +
689 + Verifier.VerifyFirewallRule("WiXToolset401 Test - 0019", expected2);
690 +
691 + var expected3 = new RuleDetails("WiXToolset401 Test - 0020")
692 + {
693 + Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW,
694 + ApplicationName = Path.Combine(Environment.GetEnvironmentVariable("ProgramFiles(x86)"), "MsiPackage", "file2.txt"),
695 + Description = "WiX Toolset firewall exception rule integration test - module 401 NotTheMergeRedirectFolder - app",
696 + Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN,
697 + EdgeTraversal = true,
698 + EdgeTraversalOptions = 1,
699 + Enabled = true,
700 + InterfaceTypes = "All",
701 + LocalAddresses = "*",
702 + LocalPorts = "40103",
703 + Profiles = Int32.MaxValue,
704 + Protocol = 6,
705 + RemoteAddresses = "*",
706 + RemotePorts = "*",
707 + SecureFlags = 0,
708 + };
709 +
710 + Verifier.VerifyFirewallRule("WiXToolset401 Test - 0020", expected3);
711 +
712 + var expected4 = new RuleDetails("WiXToolset401 Test - 0021")
713 + {
714 + Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW,
715 + Description = "WiX Toolset firewall exception rule integration test - module 401 NotTheMergeRedirectFolder - port",
716 + Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN,
717 + EdgeTraversal = false,
718 + EdgeTraversalOptions = 0,
719 + Enabled = true,
720 + InterfaceTypes = "All",
721 + LocalAddresses = "*",
722 + LocalPorts = "40104",
723 + Profiles = Int32.MaxValue,
724 + Protocol = 6,
725 + RemoteAddresses = "*",
726 + RemotePorts = "*",
727 + SecureFlags = 0,
728 + };
729 +
730 + Verifier.VerifyFirewallRule("WiXToolset401 Test - 0021", expected4);
731 +
732 + var expected5 = new RuleDetails("WiXToolset Test - 0022")
733 + {
734 + Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW,
735 + ApplicationName = Path.Combine(Environment.GetEnvironmentVariable("ProgramFiles(x86)"), "MsiPackage", "file1.txt"),
736 + Description = "WiX Toolset firewall exception rule integration test - module MergeRedirectFolder - app",
737 + Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN,
738 + EdgeTraversal = false,
739 + EdgeTraversalOptions = 0,
740 + Enabled = true,
741 + InterfaceTypes = "All",
742 + LocalAddresses = "*",
743 + LocalPorts = "50001",
744 + Profiles = Int32.MaxValue,
745 + Protocol = 6,
746 + RemoteAddresses = "*",
747 + RemotePorts = "*",
748 + SecureFlags = 0,
749 + };
750 +
751 + Verifier.VerifyFirewallRule("WiXToolset Test - 0022", expected5);
752 +
753 + var expected6 = new RuleDetails("WiXToolset Test - 0023")
754 + {
755 + Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW,
756 + Description = "WiX Toolset firewall exception rule integration test - module MergeRedirectFolder - port",
757 + Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN,
758 + EdgeTraversal = false,
759 + EdgeTraversalOptions = 0,
760 + Enabled = true,
761 + InterfaceTypes = "All",
762 + LocalAddresses = "*",
763 + LocalPorts = "50002",
764 + Profiles = Int32.MaxValue,
765 + Protocol = 6,
766 + RemoteAddresses = "*",
767 + RemotePorts = "*",
768 + SecureFlags = 0,
769 + };
770 +
771 + Verifier.VerifyFirewallRule("WiXToolset Test - 0023", expected6);
772 +
773 + var expected7 = new RuleDetails("WiXToolset Test - 0024")
774 + {
775 + Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW,
776 + ApplicationName = Path.Combine(Environment.GetEnvironmentVariable("ProgramFiles(x86)"), "MsiPackage", "file2.txt"),
777 + Description = "WiX Toolset firewall exception rule integration test - module NotTheMergeRedirectFolder - app",
778 + Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN,
779 + EdgeTraversal = false,
780 + EdgeTraversalOptions = 0,
781 + Enabled = true,
782 + InterfaceTypes = "All",
783 + LocalAddresses = "*",
784 + LocalPorts = "50003",
785 + Profiles = Int32.MaxValue,
786 + Protocol = 6,
787 + RemoteAddresses = "*",
788 + RemotePorts = "*",
789 + SecureFlags = 0,
790 + };
791 +
792 + Verifier.VerifyFirewallRule("WiXToolset Test - 0024", expected7);
793 +
794 + var expected8 = new RuleDetails("WiXToolset Test - 0025")
795 + {
796 + Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW,
797 + Description = "WiX Toolset firewall exception rule integration test - module NotTheMergeRedirectFolder - port",
798 + Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN,
799 + EdgeTraversal = false,
800 + EdgeTraversalOptions = 0,
801 + Enabled = true,
802 + InterfaceTypes = "All",
803 + LocalAddresses = "*",
804 + LocalPorts = "50004",
805 + Profiles = Int32.MaxValue,
806 + Protocol = 6,
807 + RemoteAddresses = "*",
808 + RemotePorts = "*",
809 + SecureFlags = 0,
810 + };
811 +
812 + Verifier.VerifyFirewallRule("WiXToolset Test - 0025", expected8);
813 +
814 + var expected9 = new RuleDetails("WiXToolset Test - 0026")
815 + {
816 + Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW,
817 + ApplicationName = Path.Combine(Environment.GetEnvironmentVariable("ProgramFiles(x86)"), "MsiPackage", "package.wxs"),
818 + Description = "WiX Toolset firewall exception rule integration test - package app",
819 + Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN,
820 + EdgeTraversal = false,
821 + EdgeTraversalOptions = 0,
822 + Enabled = true,
823 + InterfaceTypes = "All",
824 + LocalAddresses = "*",
825 + LocalPorts = "20001",
826 + Profiles = Int32.MaxValue,
827 + Protocol = 6,
828 + RemoteAddresses = "*",
829 + RemotePorts = "*",
830 + SecureFlags = 0,
831 + };
832 +
833 + Verifier.VerifyFirewallRule("WiXToolset Test - 0026", expected9);
834 +
835 + var expected10 = new RuleDetails("WiXToolset Test - 0027")
836 + {
837 + Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW,
838 + Description = "WiX Toolset firewall exception rule integration test - package port",
839 + Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN,
840 + EdgeTraversal = false,
841 + EdgeTraversalOptions = 0,
842 + Enabled = true,
843 + InterfaceTypes = "All",
844 + LocalAddresses = "*",
845 + LocalPorts = "20002",
846 + Profiles = Int32.MaxValue,
847 + Protocol = 6,
848 + RemoteAddresses = "*",
849 + RemotePorts = "*",
850 + SecureFlags = 0,
851 + };
852 +
853 + Verifier.VerifyFirewallRule("WiXToolset Test - 0027", expected10);
854 +
855 + product.UninstallProduct(MSIExec.MSIExecReturnCode.SUCCESS);
856 +
857 + // verify the firewall exceptions have been removed.
858 + Assert.False(Verifier.FirewallRuleExists("WiXToolset401 Test - 0018"));
859 + Assert.False(Verifier.FirewallRuleExists("WiXToolset401 Test - 0019"));
860 + Assert.False(Verifier.FirewallRuleExists("WiXToolset401 Test - 0020"));
861 + Assert.False(Verifier.FirewallRuleExists("WiXToolset401 Test - 0021"));
862 + Assert.False(Verifier.FirewallRuleExists("WiXToolset Test - 0022"));
863 + Assert.False(Verifier.FirewallRuleExists("WiXToolset Test - 0023"));
864 + Assert.False(Verifier.FirewallRuleExists("WiXToolset Test - 0024"));
865 + Assert.False(Verifier.FirewallRuleExists("WiXToolset Test - 0025"));
866 + Assert.False(Verifier.FirewallRuleExists("WiXToolset Test - 0026"));
867 + Assert.False(Verifier.FirewallRuleExists("WiXToolset Test - 0027"));
868 + }
869 +
870 + [RuntimeFact]
871 + public void ServiceNameIsPassedIntoNestedRules()
872 + {
873 + var product = this.CreatePackageInstaller("NestedService");
874 + product.InstallProduct(MSIExec.MSIExecReturnCode.SUCCESS);
875 +
876 + var expected1 = new RuleDetails("WiXToolset Test - 0031")
877 + {
878 + Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW,
879 + Protocol = 256,
880 + LocalAddresses = "*",
881 + RemoteAddresses = "*",
882 + Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN,
883 + Description = "WiX Toolset firewall exception rule integration test - service property",
884 + EdgeTraversal = false,
885 + EdgeTraversalOptions = 0,
886 + Enabled = true,
887 + InterfaceTypes = "All",
888 + Profiles = Int32.MaxValue,
889 + SecureFlags = 0,
890 + ServiceName = "Spooler",
891 + };
892 +
893 + Verifier.VerifyFirewallRule("WiXToolset Test - 0031", expected1);
894 +
895 + var expected2 = new RuleDetails("WiXToolset Test - 0032")
896 + {
897 + Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW,
898 + Protocol = 256,
899 + LocalAddresses = "*",
900 + RemoteAddresses = "*",
901 + Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN,
902 + Description = "WiX Toolset firewall exception rule integration test - ServiceConfig",
903 + EdgeTraversal = false,
904 + EdgeTraversalOptions = 0,
905 + Enabled = true,
906 + InterfaceTypes = "All",
907 + Profiles = Int32.MaxValue,
908 + SecureFlags = 0,
909 + ServiceName = "Spooler",
910 + };
911 +
912 + Verifier.VerifyFirewallRule("WiXToolset Test - 0032", expected2);
913 +
914 + var expected3 = new RuleDetails("WiXToolset Test - 0033")
915 + {
916 + Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW,
917 + Protocol = 256,
918 + LocalAddresses = "*",
919 + RemoteAddresses = "*",
920 + Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN,
921 + Description = "WiX Toolset firewall exception rule integration test - ServiceInstall",
922 + EdgeTraversal = false,
923 + EdgeTraversalOptions = 0,
924 + Enabled = true,
925 + InterfaceTypes = "All",
926 + Profiles = Int32.MaxValue,
927 + SecureFlags = 0,
928 + ServiceName = "WixTestFirewallSrv",
929 + };
930 +
931 + Verifier.VerifyFirewallRule("WiXToolset Test - 0033", expected3);
932 +
933 + product.UninstallProduct(MSIExec.MSIExecReturnCode.SUCCESS);
934 +
935 + // verify the firewall exceptions have been removed.
936 + Assert.False(Verifier.FirewallRuleExists("WiXToolset Test - 0031"));
937 + Assert.False(Verifier.FirewallRuleExists("WiXToolset Test - 0032"));
938 + Assert.False(Verifier.FirewallRuleExists("WiXToolset Test - 0033"));
939 + }
940 +
941 + [RuntimeFact]
942 + public void SucceedWhenEnableOnlyFlagIsSet()
943 + {
944 + var product = this.CreatePackageInstaller("FirewallRulesProperties");
945 + product.InstallProduct(MSIExec.MSIExecReturnCode.SUCCESS);
946 +
947 + var expected1 = new RuleDetails("WiXToolset Test - 0028")
948 + {
949 + Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW,
950 + Protocol = 256,
951 + LocalAddresses = "*",
952 + RemoteAddresses = "*",
953 + Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN,
954 + EdgeTraversal = false,
955 + EdgeTraversalOptions = 0,
956 + Enabled = true,
957 + InterfaceTypes = "All",
958 + Profiles = Int32.MaxValue,
959 + SecureFlags = 0,
960 + };
961 +
962 + Verifier.VerifyFirewallRule("WiXToolset Test - 0028", expected1);
963 +
964 + Verifier.DisableFirewallRule("WiXToolset Test - 0028");
965 +
966 + var args = new[]
967 + {
968 + "LOCALPORT=3456",
969 + "PROTOCOL=6",
970 + "PROGRAM=ShouldBeUnchanged",
971 + "PROFILE=2",
972 + "DESCRIPTION=ShouldBeUnchanged",
973 + "REMOTESCOPE=ShouldBeUnchanged",
974 + "EDGETRAVERSAL=3",
975 + "ENABLED=1",
976 + "GROUPING=ShouldBeUnchanged",
977 + "ICMPTYPES=ShouldBeUnchanged",
978 + "INTERFACE=ShouldBeUnchanged",
979 + "INTERFACETYPE=ShouldBeUnchanged",
980 + "LOCALSCOPE=ShouldBeUnchanged",
981 + "REMOTEPORT=60000",
982 + "SERVICE=ShouldBeUnchanged",
983 + "PACKAGEID=ShouldBeUnchanged",
984 + "LOCALUSERS=ShouldBeUnchanged",
985 + "LOCALOWNER=ShouldBeUnchanged",
986 + "REMOTEMACHINES=ShouldBeUnchanged",
987 + "REMOTEUSERS=ShouldBeUnchanged",
988 + "SECUREFLAGS=15",
989 + "REMOTEADDRESS=ShouldBeUnchanged",
990 + "LOCALADDRESS=ShouldBeUnchanged",
991 + };
992 +
993 + product.RepairProduct(MSIExec.MSIExecReturnCode.SUCCESS, args);
994 +
995 + var expected2 = new RuleDetails("WiXToolset Test - 0028")
996 + {
997 + Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW,
998 + Protocol = 256,
999 + LocalAddresses = "*",
1000 + RemoteAddresses = "*",
1001 + Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN,
1002 + EdgeTraversal = false,
1003 + EdgeTraversalOptions = 0,
1004 + Enabled = true,
1005 + InterfaceTypes = "All",
1006 + Profiles = Int32.MaxValue,
1007 + SecureFlags = 0,
1008 + };
1009 +
1010 + Verifier.VerifyFirewallRule("WiXToolset Test - 0028", expected2);
1011 +
1012 + product.UninstallProduct(MSIExec.MSIExecReturnCode.SUCCESS);
1013 +
1014 + // verify the firewall exceptions have been removed.
1015 + Assert.False(Verifier.FirewallRuleExists("WiXToolset Test - 0028"));
1016 + }
1017 +
1018 + [RuntimeFact]
1019 + public void SucceedWhenDoNothingFlagIsSet()
1020 + {
1021 + var product = this.CreatePackageInstaller("FirewallRulesProperties");
1022 + product.InstallProduct(MSIExec.MSIExecReturnCode.SUCCESS);
1023 +
1024 + var expected1 = new RuleDetails("WiXToolset Test - 0029")
1025 + {
1026 + Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW,
1027 + Protocol = 256,
1028 + LocalAddresses = "*",
1029 + RemoteAddresses = "*",
1030 + Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN,
1031 + EdgeTraversal = false,
1032 + EdgeTraversalOptions = 0,
1033 + Enabled = true,
1034 + InterfaceTypes = "All",
1035 + Profiles = Int32.MaxValue,
1036 + SecureFlags = 0,
1037 + };
1038 +
1039 + Verifier.VerifyFirewallRule("WiXToolset Test - 0029", expected1);
1040 + Verifier.DisableFirewallRule("WiXToolset Test - 0029");
1041 +
1042 + var args = new[]
1043 + {
1044 + "INTERFACE=ShouldBeUnchanged",
1045 + "INTERFACETYPE=ShouldBeUnchanged",
1046 + "REMOTEADDRESS=ShouldBeUnchanged",
1047 + "LOCALADDRESS=ShouldBeUnchanged",
1048 + };
1049 +
1050 + product.RepairProduct(MSIExec.MSIExecReturnCode.SUCCESS, args);
1051 +
1052 + var expected2 = new RuleDetails("WiXToolset Test - 0029")
1053 + {
1054 + Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW,
1055 + Protocol = 256,
1056 + LocalAddresses = "*",
1057 + RemoteAddresses = "*",
1058 + Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN,
1059 + EdgeTraversal = false,
1060 + EdgeTraversalOptions = 0,
1061 + Enabled = false, // remains as disabled after the repair
1062 + InterfaceTypes = "All",
1063 + Profiles = Int32.MaxValue,
1064 + SecureFlags = 0,
1065 + };
1066 +
1067 + Verifier.VerifyFirewallRule("WiXToolset Test - 0029", expected2);
1068 +
1069 + product.UninstallProduct(MSIExec.MSIExecReturnCode.SUCCESS);
1070 +
1071 + // verify the firewall exceptions have been removed.
1072 + Assert.False(Verifier.FirewallRuleExists("WiXToolset Test - 0029"));
1073 + }
1074 +
1075 + [RuntimeFact]
1076 + public void SucceedWhenNoFlagIsSet()
1077 + {
1078 + var product = this.CreatePackageInstaller("FirewallRulesProperties");
1079 + product.InstallProduct(MSIExec.MSIExecReturnCode.SUCCESS);
1080 +
1081 + var expected1 = new RuleDetails("WiXToolset Test - 0030")
1082 + {
1083 + Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW,
1084 + Protocol = 256,
1085 + LocalAddresses = "*",
1086 + RemoteAddresses = "*",
1087 + Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN,
1088 + EdgeTraversal = false,
1089 + EdgeTraversalOptions = 0,
1090 + Enabled = true,
1091 + InterfaceTypes = "All",
1092 + Profiles = Int32.MaxValue,
1093 + SecureFlags = 0,
1094 + };
1095 +
1096 + Verifier.VerifyFirewallRule("WiXToolset Test - 0030", expected1);
1097 + Verifier.DisableFirewallRule("WiXToolset Test - 0030");
1098 +
1099 + var names = NetworkInterface.GetAllNetworkInterfaces()
1100 + .Take(2)
1101 + .Select(ni => ni.Name);
1102 +
1103 + var args = names.Select((name, idx) => $"INTERFACE{idx + 1}=\"{name}\"")
1104 + .Concat(new[]
1105 + {
1106 + "INTERFACETYPE1=Wireless",
1107 + "INTERFACETYPE2=Lan",
1108 + "REMOTEADDRESS1=DHCP",
1109 + "REMOTEADDRESS2=LocalSubnet",
1110 + "LOCALADDRESS1=127.0.0.1",
1111 + "LOCALADDRESS2=192.168.1.1",
1112 + })
1113 + .ToArray();
1114 +
1115 + product.RepairProduct(MSIExec.MSIExecReturnCode.SUCCESS, args);
1116 +
1117 + var expected2 = new RuleDetails("WiXToolset Test - 0030")
1118 + {
1119 + Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW,
1120 + Protocol = 256,
1121 + LocalAddresses = "127.0.0.1/255.255.255.255,192.168.1.1/255.255.255.255",
1122 + RemoteAddresses = "LocalSubnet,DHCP",
1123 + Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN,
1124 + Description = "",
1125 + EdgeTraversal = false,
1126 + EdgeTraversalOptions = 0,
1127 + Enabled = true,
1128 + Interfaces = names.ToArray(),
1129 + InterfaceTypes = "Lan,Wireless",
1130 + Profiles = Int32.MaxValue,
1131 + SecureFlags = 0,
1132 + };
1133 +
1134 + Verifier.VerifyFirewallRule("WiXToolset Test - 0030", expected2);
1135 +
1136 + product.UninstallProduct(MSIExec.MSIExecReturnCode.SUCCESS);
1137 +
1138 + // verify the firewall exceptions have been removed.
1139 + Assert.False(Verifier.FirewallRuleExists("WiXToolset Test - 0030"));
1140 + }
1141 }
1142 }
src/test/msi/WixToolsetTest.MsiE2E/WixToolsetTest.MsiE2E.csproj
+1
@@ -29,6 +29,7 @@
29
30 <ItemGroup>
31 <PackageReference Include="Microsoft.Win32.Registry" />
32 + <PackageReference Include="System.Net.NetworkInformation" />
33 <PackageReference Include="System.Security.Principal.Windows" />
34 <PackageReference Include="WixInternal.TestSupport" />
35 <PackageReference Include="WixToolset.Data" />