summaryrefslogtreecommitdiff
path: root/src/ext/Firewall/wixext/FirewallCompiler.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/ext/Firewall/wixext/FirewallCompiler.cs')
-rw-r--r--src/ext/Firewall/wixext/FirewallCompiler.cs623
1 files changed, 563 insertions, 60 deletions
diff --git a/src/ext/Firewall/wixext/FirewallCompiler.cs b/src/ext/Firewall/wixext/FirewallCompiler.cs
index ed49ba9c..c4a5318c 100644
--- a/src/ext/Firewall/wixext/FirewallCompiler.cs
+++ b/src/ext/Firewall/wixext/FirewallCompiler.cs
@@ -35,7 +35,7 @@ namespace WixToolset.Firewall
35 switch (element.Name.LocalName) 35 switch (element.Name.LocalName)
36 { 36 {
37 case "FirewallException": 37 case "FirewallException":
38 this.ParseFirewallExceptionElement(intermediate, section, element, fileComponentId, fileId); 38 this.ParseFirewallExceptionElement(intermediate, section, parentElement, element, fileComponentId, fileId, null);
39 break; 39 break;
40 default: 40 default:
41 this.ParseHelper.UnexpectedElement(parentElement, element); 41 this.ParseHelper.UnexpectedElement(parentElement, element);
@@ -48,7 +48,35 @@ namespace WixToolset.Firewall
48 switch (element.Name.LocalName) 48 switch (element.Name.LocalName)
49 { 49 {
50 case "FirewallException": 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);
52 break; 80 break;
53 default: 81 default:
54 this.ParseHelper.UnexpectedElement(parentElement, element); 82 this.ParseHelper.UnexpectedElement(parentElement, element);
@@ -64,10 +92,12 @@ namespace WixToolset.Firewall
64 /// <summary> 92 /// <summary>
65 /// Parses a FirewallException element. 93 /// Parses a FirewallException element.
66 /// </summary> 94 /// </summary>
95 /// <param name="parentElement">The parent element of the one being parsed.</param>
67 /// <param name="element">The element to parse.</param> 96 /// <param name="element">The element to parse.</param>
68 /// <param name="componentId">Identifier of the component that owns this firewall exception.</param> 97 /// <param name="componentId">Identifier of the component that owns this firewall exception.</param>
69 /// <param name="fileId">The file identifier of the parent element (null if nested under Component).</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)
71 { 101 {
72 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); 102 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
73 Identifier id = null; 103 Identifier id = null;
@@ -76,12 +106,32 @@ namespace WixToolset.Firewall
76 string file = null; 106 string file = null;
77 string program = null; 107 string program = null;
78 string port = null; 108 string port = null;
79 int? protocol = null; 109 string protocol = null;
80 int? profile = null; 110 string profile = null;
81 string scope = null; 111 string scope = null;
82 string remoteAddresses = null; 112 string remoteAddresses = null;
83 string description = null; 113 string description = null;
84 int? direction = 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;
85 135
86 foreach (var attrib in element.Attributes()) 136 foreach (var attrib in element.Attributes())
87 { 137 {
@@ -96,9 +146,9 @@ namespace WixToolset.Firewall
96 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); 146 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
97 break; 147 break;
98 case "File": 148 case "File":
99 if (null != fileId) 149 if (fileId != null)
100 { 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));
102 } 152 }
103 else 153 else
104 { 154 {
@@ -106,15 +156,31 @@ namespace WixToolset.Firewall
106 } 156 }
107 break; 157 break;
108 case "IgnoreFailure": 158 case "IgnoreFailure":
109 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) 159 if (this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) == YesNoType.Yes)
110 { 160 {
111 attributes |= 0x1; // feaIgnoreFailures 161 attributes |= 0x1; // feaIgnoreFailures
112 } 162 }
113 break; 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;
114 case "Program": 180 case "Program":
115 if (null != fileId) 181 if (fileId != null)
116 { 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));
118 } 184 }
119 else 185 else
120 { 186 {
@@ -125,22 +191,28 @@ namespace WixToolset.Firewall
125 port = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); 191 port = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
126 break; 192 break;
127 case "Protocol": 193 case "Protocol":
128 var protocolValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); 194 protocolValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
129 switch (protocolValue) 195 switch (protocolValue)
130 { 196 {
197 case FirewallConstants.IntegerNotSetString:
198 break;
199
131 case "tcp": 200 case "tcp":
132 protocol = FirewallConstants.NET_FW_IP_PROTOCOL_TCP; 201 protocol = FirewallConstants.NET_FW_IP_PROTOCOL_TCP.ToString();
133 break; 202 break;
134 case "udp": 203 case "udp":
135 protocol = FirewallConstants.NET_FW_IP_PROTOCOL_UDP; 204 protocol = FirewallConstants.NET_FW_IP_PROTOCOL_UDP.ToString();
136 break; 205 break;
206
137 default: 207 default:
138 int parsedProtocol; 208 protocol = protocolValue;
139 if (!Int32.TryParse(protocolValue, out parsedProtocol) || parsedProtocol > 255 || parsedProtocol < 0) 209 if (!this.ParseHelper.ContainsProperty(protocolValue))
140 { 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 }
142 } 215 }
143 protocol = parsedProtocol;
144 break; 216 break;
145 } 217 }
146 break; 218 break;
@@ -167,7 +239,11 @@ namespace WixToolset.Firewall
167 remoteAddresses = "DefaultGateway"; 239 remoteAddresses = "DefaultGateway";
168 break; 240 break;
169 default: 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 }
171 break; 247 break;
172 } 248 }
173 break; 249 break;
@@ -176,19 +252,23 @@ namespace WixToolset.Firewall
176 switch (profileValue) 252 switch (profileValue)
177 { 253 {
178 case "domain": 254 case "domain":
179 profile = FirewallConstants.NET_FW_PROFILE2_DOMAIN; 255 profile = FirewallConstants.NET_FW_PROFILE2_DOMAIN.ToString();
180 break; 256 break;
181 case "private": 257 case "private":
182 profile = FirewallConstants.NET_FW_PROFILE2_PRIVATE; 258 profile = FirewallConstants.NET_FW_PROFILE2_PRIVATE.ToString();
183 break; 259 break;
184 case "public": 260 case "public":
185 profile = FirewallConstants.NET_FW_PROFILE2_PUBLIC; 261 profile = FirewallConstants.NET_FW_PROFILE2_PUBLIC.ToString();
186 break; 262 break;
187 case "all": 263 case "all":
188 profile = FirewallConstants.NET_FW_PROFILE2_ALL; 264 profile = FirewallConstants.NET_FW_PROFILE2_ALL.ToString();
189 break; 265 break;
190 default: 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 }
192 break; 272 break;
193 } 273 }
194 break; 274 break;
@@ -200,6 +280,196 @@ namespace WixToolset.Firewall
200 ? FirewallConstants.NET_FW_RULE_DIR_OUT 280 ? FirewallConstants.NET_FW_RULE_DIR_OUT
201 : FirewallConstants.NET_FW_RULE_DIR_IN; 281 : FirewallConstants.NET_FW_RULE_DIR_IN;
202 break; 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;
203 default: 473 default:
204 this.ParseHelper.UnexpectedAttribute(element, attrib); 474 this.ParseHelper.UnexpectedAttribute(element, attrib);
205 break; 475 break;
@@ -211,7 +481,7 @@ namespace WixToolset.Firewall
211 } 481 }
212 } 482 }
213 483
214 // parse RemoteAddress children 484 // parse children
215 foreach (var child in element.Elements()) 485 foreach (var child in element.Elements())
216 { 486 {
217 if (this.Namespace == child.Name.Namespace) 487 if (this.Namespace == child.Name.Namespace)
@@ -219,7 +489,7 @@ namespace WixToolset.Firewall
219 switch (child.Name.LocalName) 489 switch (child.Name.LocalName)
220 { 490 {
221 case "RemoteAddress": 491 case "RemoteAddress":
222 if (null != scope) 492 if (scope != null)
223 { 493 {
224 this.Messaging.Write(FirewallErrors.IllegalRemoteAddressWithScopeAttribute(sourceLineNumbers)); 494 this.Messaging.Write(FirewallErrors.IllegalRemoteAddressWithScopeAttribute(sourceLineNumbers));
225 } 495 }
@@ -228,6 +498,37 @@ namespace WixToolset.Firewall
228 this.ParseRemoteAddressElement(intermediate, section, child, ref remoteAddresses); 498 this.ParseRemoteAddressElement(intermediate, section, child, ref remoteAddresses);
229 } 499 }
230 break; 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
231 default: 532 default:
232 this.ParseHelper.UnexpectedElement(element, child); 533 this.ParseHelper.UnexpectedElement(element, child);
233 break; 534 break;
@@ -239,54 +540,84 @@ namespace WixToolset.Firewall
239 } 540 }
240 } 541 }
241 542
242 if (null == id) 543 if (id == null)
243 { 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);
245 } 547 }
246 548
247 // Name is required 549 // Name is required
248 if (null == name) 550 if (name == null)
249 { 551 {
250 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name")); 552 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
251 } 553 }
252 554
253 // Scope or child RemoteAddress(es) are required 555 if (service == null)
254 if (null == remoteAddresses)
255 { 556 {
256 this.Messaging.Write(ErrorMessages.ExpectedAttributeOrElement(sourceLineNumbers, element.Name.LocalName, "Scope", "RemoteAddress")); 557 service = serviceName;
257 } 558 }
258 559
259 // can't have both Program and File 560 // can't have both Program and File
260 if (null != program && null != file) 561 if (program != null && file != null)
261 { 562 {
262 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "File", "Program")); 563 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "File", "Program"));
263 } 564 }
264 565
265 // must be nested under File, have File or Program attributes, or have Port attribute 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.
266 if (String.IsNullOrEmpty(fileId) && String.IsNullOrEmpty(file) && String.IsNullOrEmpty(program) && String.IsNullOrEmpty(port)) 567 if (edgeTraversal == FirewallConstants.NET_FW_EDGE_TRAVERSAL_TYPE_DEFER_TO_USER.ToString())
267 { 568 {
268 this.Messaging.Write(FirewallErrors.NoExceptionSpecified(sourceLineNumbers)); 569 if (protocol != null && !(protocol == FirewallConstants.NET_FW_IP_PROTOCOL_TCP.ToString() || protocol == FirewallConstants.NET_FW_IP_PROTOCOL_UDP.ToString()))
269 } 570 {
571 this.Messaging.Write(ErrorMessages.IllegalAttributeValueWithLegalList(sourceLineNumbers, element.Name.LocalName, "Protocol", protocolValue, "tcp,udp"));
572 }
270 573
271 // Ports can only be specified if the protocol is TCP or UDP. 574 if (String.IsNullOrEmpty(fileId) && String.IsNullOrEmpty(file) && String.IsNullOrEmpty(program))
272 if (!String.IsNullOrEmpty(port) && protocol.HasValue)
273 {
274 switch(protocol.Value)
275 { 575 {
276 case FirewallConstants.NET_FW_IP_PROTOCOL_TCP: 576 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Program", "EdgeTraversal", "DeferToUser"));
277 case FirewallConstants.NET_FW_IP_PROTOCOL_UDP: 577 }
278 break;
279 578
280 default: 579 if (port != null)
281 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "Port", "Protocol", protocol.Value.ToString())); 580 {
282 break; 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 }
283 } 614 }
284 } 615 }
285 616
286 if (!this.Messaging.EncounteredError) 617 if (!this.Messaging.EncounteredError)
287 { 618 {
288 // at this point, File attribute and File parent element are treated the same 619 // at this point, File attribute and File parent element are treated the same
289 if (null != file) 620 if (file != null)
290 { 621 {
291 fileId = file; 622 fileId = file;
292 } 623 }
@@ -295,28 +626,38 @@ namespace WixToolset.Firewall
295 { 626 {
296 Name = name, 627 Name = name,
297 RemoteAddresses = remoteAddresses, 628 RemoteAddresses = remoteAddresses,
298 Profile = profile ?? FirewallConstants.NET_FW_PROFILE2_ALL,
299 ComponentRef = componentId, 629 ComponentRef = componentId,
300 Description = description, 630 Description = description,
301 Direction = direction ?? FirewallConstants.NET_FW_RULE_DIR_IN, 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,
302 }); 651 });
303 652
304 if (!String.IsNullOrEmpty(port)) 653 if (String.IsNullOrEmpty(protocol))
305 { 654 {
306 symbol.Port = port; 655 if (!String.IsNullOrEmpty(port) || !String.IsNullOrEmpty(remotePort))
307
308 if (!protocol.HasValue)
309 { 656 {
310 // default protocol is "TCP" 657 symbol.Protocol = FirewallConstants.NET_FW_IP_PROTOCOL_TCP.ToString();
311 protocol = FirewallConstants.NET_FW_IP_PROTOCOL_TCP;
312 } 658 }
313 } 659 }
314 660
315 if (protocol.HasValue)
316 {
317 symbol.Protocol = protocol.Value;
318 }
319
320 if (!String.IsNullOrEmpty(fileId)) 661 if (!String.IsNullOrEmpty(fileId))
321 { 662 {
322 symbol.Program = $"[#{fileId}]"; 663 symbol.Program = $"[#{fileId}]";
@@ -327,7 +668,7 @@ namespace WixToolset.Firewall
327 symbol.Program = program; 668 symbol.Program = program;
328 } 669 }
329 670
330 if (CompilerConstants.IntegerNotSet != attributes) 671 if (attributes != CompilerConstants.IntegerNotSet)
331 { 672 {
332 symbol.Attributes = attributes; 673 symbol.Attributes = attributes;
333 } 674 }
@@ -382,5 +723,167 @@ namespace WixToolset.Firewall
382 } 723 }
383 } 724 }
384 } 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 }
385 } 888 }
386} 889}