main
cs 901 lines 43.8 KB
Raw
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 namespace WixToolset.Firewall
4 {
5 using System;
6 using System.Collections.Generic;
7 using System.Xml.Linq;
8 using WixToolset.Data;
9 using WixToolset.Extensibility;
10 using WixToolset.Extensibility.Data;
11 using WixToolset.Firewall.Symbols;
12
13 /// <summary>
14 /// The compiler for the WiX Toolset Firewall Extension.
15 /// </summary>
16 public sealed class FirewallCompiler : BaseCompilerExtension
17 {
18 public override XNamespace Namespace => FirewallConstants.Namespace;
19
20 /// <summary>
21 /// Processes an element for the Compiler.
22 /// </summary>
23 /// <param name="sourceLineNumbers">Source line number for the parent element.</param>
24 /// <param name="parentElement">Parent element of element to process.</param>
25 /// <param name="element">Element to process.</param>
26 /// <param name="contextValues">Extra information about the context in which this element is being parsed.</param>
27 public override void ParseElement(Intermediate intermediate, IntermediateSection section, XElement parentElement, XElement element, IDictionary<string, string> context)
28 {
29 switch (parentElement.Name.LocalName)
30 {
31 case "File":
32 var fileId = context["FileId"];
33 var fileComponentId = context["ComponentId"];
34
35 switch (element.Name.LocalName)
36 {
37 case "FirewallException":
38 this.ParseFirewallExceptionElement(intermediate, section, parentElement, element, fileComponentId, fileId, null);
39 break;
40 default:
41 this.ParseHelper.UnexpectedElement(parentElement, element);
42 break;
43 }
44 break;
45 case "Component":
46 var componentId = context["ComponentId"];
47
48 switch (element.Name.LocalName)
49 {
50 case "FirewallException":
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);
83 break;
84 }
85 break;
86 default:
87 this.ParseHelper.UnexpectedElement(parentElement, element);
88 break;
89 }
90 }
91
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>
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;
104 string name = null;
105 int attributes = 0;
106 string file = null;
107 string program = null;
108 string port = 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 {
138 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
139 {
140 switch (attrib.Name.LocalName)
141 {
142 case "Id":
143 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
144 break;
145 case "Name":
146 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
147 break;
148 case "File":
149 if (fileId != null)
150 {
151 this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, "File", parentElement.Name.LocalName));
152 }
153 else
154 {
155 file = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
156 }
157 break;
158 case "Program":
159 if (fileId != null)
160 {
161 this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, "Program", parentElement.Name.LocalName));
162 }
163 else
164 {
165 program = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
166 }
167 break;
168 case "IgnoreFailure":
169 if (this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) == YesNoType.Yes)
170 {
171 attributes |= 0x1; // feaIgnoreFailures
172 }
173 break;
174 case "OnUpdate":
175 var onupdate = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
176 switch (onupdate)
177 {
178 case "doNothing":
179 attributes |= 0x2; // feaIgnoreUpdates
180 break;
181 case "enableOnly":
182 attributes |= 0x4; // feaEnableOnUpdate
183 break;
184
185 default:
186 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "OnUpdate", onupdate, "enableOnly", "doNothing"));
187 break;
188 }
189 break;
190 case "Port":
191 port = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
192 break;
193 case "Protocol":
194 protocolValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
195 switch (protocolValue)
196 {
197 case FirewallConstants.IntegerNotSetString:
198 break;
199
200 case "tcp":
201 protocol = FirewallConstants.NET_FW_IP_PROTOCOL_TCP.ToString();
202 break;
203 case "udp":
204 protocol = FirewallConstants.NET_FW_IP_PROTOCOL_UDP.ToString();
205 break;
206
207 default:
208 protocol = protocolValue;
209 if (!this.ParseHelper.ContainsProperty(protocolValue))
210 {
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 }
216 break;
217 }
218 break;
219 case "Scope":
220 scope = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
221 switch (scope)
222 {
223 case "any":
224 remoteAddresses = "*";
225 break;
226 case "localSubnet":
227 remoteAddresses = "LocalSubnet";
228 break;
229 case "DNS":
230 case "dns":
231 remoteAddresses = "dns";
232 break;
233 case "DHCP":
234 case "dhcp":
235 remoteAddresses = "dhcp";
236 break;
237 case "WINS":
238 case "wins":
239 remoteAddresses = "wins";
240 break;
241 case "defaultGateway":
242 remoteAddresses = "DefaultGateway";
243 break;
244 default:
245 remoteAddresses = scope;
246 if (!this.ParseHelper.ContainsProperty(scope))
247 {
248 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "Scope", scope, "any", "localSubnet", "dns", "dhcp", "wins", "defaultGateway"));
249 }
250 break;
251 }
252 break;
253 case "Profile":
254 var profileValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
255 switch (profileValue)
256 {
257 case "domain":
258 profile = FirewallConstants.NET_FW_PROFILE2_DOMAIN.ToString();
259 break;
260 case "private":
261 profile = FirewallConstants.NET_FW_PROFILE2_PRIVATE.ToString();
262 break;
263 case "public":
264 profile = FirewallConstants.NET_FW_PROFILE2_PUBLIC.ToString();
265 break;
266 case "all":
267 profile = FirewallConstants.NET_FW_PROFILE2_ALL.ToString();
268 break;
269 default:
270 profile = profileValue;
271 if (!this.ParseHelper.ContainsProperty(profileValue))
272 {
273 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "Profile", profileValue, "domain", "private", "public", "all"));
274 }
275 break;
276 }
277 break;
278 case "Description":
279 description = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
280 break;
281 case "Outbound":
282 direction = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) == YesNoType.Yes
283 ? FirewallConstants.NET_FW_RULE_DIR_OUT
284 : FirewallConstants.NET_FW_RULE_DIR_IN;
285 break;
286 case "Action":
287 action = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
288 switch (action)
289 {
290 case "block":
291 action = "0";
292 break;
293 case "allow":
294 action = "1";
295 break;
296
297 default:
298 if (!this.ParseHelper.ContainsProperty(action))
299 {
300 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "Action", action, "allow", "block"));
301 }
302 break;
303 }
304 break;
305 case "EdgeTraversal":
306 edgeTraversal = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
307 switch (edgeTraversal)
308 {
309 case "deny":
310 edgeTraversal = FirewallConstants.NET_FW_EDGE_TRAVERSAL_TYPE_DENY.ToString();
311 break;
312 case "allow":
313 edgeTraversal = FirewallConstants.NET_FW_EDGE_TRAVERSAL_TYPE_ALLOW.ToString();
314 break;
315 case "deferToApp":
316 attributes |= 0x8; // feaAddINetFwRule2
317 edgeTraversal = FirewallConstants.NET_FW_EDGE_TRAVERSAL_TYPE_DEFER_TO_APP.ToString();
318 break;
319 case "deferToUser":
320 attributes |= 0x8; // feaAddINetFwRule2
321 edgeTraversal = FirewallConstants.NET_FW_EDGE_TRAVERSAL_TYPE_DEFER_TO_USER.ToString();
322 break;
323
324 default:
325 if (!this.ParseHelper.ContainsProperty(edgeTraversal))
326 {
327 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "EdgeTraversal", edgeTraversal, "allow", "deferToApp", "deferToUser", "deny"));
328 }
329 break;
330 }
331 break;
332 case "Enabled":
333 enabled = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
334 if (!this.ParseHelper.ContainsProperty(enabled))
335 {
336 switch (this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
337 {
338 case YesNoType.Yes:
339 enabled = "1";
340 break;
341 case YesNoType.No:
342 enabled = "0";
343 break;
344 default:
345 this.Messaging.Write(ErrorMessages.IllegalYesNoValue(sourceLineNumbers, element.Name.LocalName, "Enabled", enabled));
346 break;
347 }
348 }
349 break;
350 case "Grouping":
351 grouping = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
352 break;
353 case "IcmpTypesAndCodes":
354 icmpTypesAndCodes = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
355 break;
356 case "Interface":
357 interfaceValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
358 interfaces = interfaceValue;
359 break;
360 case "InterfaceType":
361 interfaceTypeValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
362 switch (interfaceTypeValue)
363 {
364 case "remoteAccess":
365 case "wireless":
366 case "lan":
367 case "all":
368 break;
369
370 default:
371 if (!this.ParseHelper.ContainsProperty(interfaceTypeValue))
372 {
373 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "InterfaceType", interfaceTypeValue, "remoteAccess", "wireless", "lan", "all"));
374 }
375 break;
376 }
377 interfaceTypes = interfaceTypeValue;
378 break;
379 case "LocalScope":
380 localScope = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
381 switch (localScope)
382 {
383 case "any":
384 localAddresses = "*";
385 break;
386 case "localSubnet":
387 localAddresses = "LocalSubnet";
388 break;
389 case "DNS":
390 case "dns":
391 localAddresses = "dns";
392 break;
393 case "DHCP":
394 case "dhcp":
395 localAddresses = "dhcp";
396 break;
397 case "WINS":
398 case "wins":
399 localAddresses = "wins";
400 break;
401 case "defaultGateway":
402 localAddresses = "DefaultGateway";
403 break;
404
405 default:
406 if (!this.ParseHelper.ContainsProperty(localScope))
407 {
408 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "LocalScope", localScope, "any", "localSubnet", "dns", "dhcp", "wins", "defaultGateway"));
409 }
410 else
411 {
412 localAddresses = localScope;
413 }
414 break;
415 }
416 break;
417 case "RemotePort":
418 remotePort = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
419 break;
420 case "Service":
421 if (serviceName != null)
422 {
423 this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, "Service", parentElement.Name.LocalName));
424 }
425 else
426 {
427 service = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
428 }
429 break;
430 case "LocalAppPackageId":
431 localAppPackageId = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
432 attributes |= 0x10; // feaAddINetFwRule3
433 break;
434 case "LocalUserAuthorizedList":
435 localUserAuthorizedList = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
436 attributes |= 0x10; // feaAddINetFwRule3
437 break;
438 case "LocalUserOwner":
439 localUserOwner = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
440 attributes |= 0x10; // feaAddINetFwRule3
441 break;
442 case "RemoteMachineAuthorizedList":
443 remoteMachineAuthorizedList = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
444 attributes |= 0x10; // feaAddINetFwRule3
445 break;
446 case "RemoteUserAuthorizedList":
447 remoteUserAuthorizedList = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
448 attributes |= 0x10; // feaAddINetFwRule3
449 break;
450 case "IPSecSecureFlags":
451 secureFlags = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
452 attributes |= 0x10; // feaAddINetFwRule3
453 if (!this.ParseHelper.ContainsProperty(secureFlags))
454 {
455 switch (secureFlags)
456 {
457 case "none":
458 secureFlags = "0";
459 break;
460 case "noEncapsulation":
461 secureFlags = "1";
462 break;
463 case "withIntegrity":
464 secureFlags = "2";
465 break;
466 case "negotiateEncryption":
467 secureFlags = "3";
468 break;
469 case "encrypt":
470 secureFlags = "4";
471 break;
472 default:
473 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "IPSecSecureFlags", secureFlags, "none", "noEncapsulation", "withIntegrity", "negotiateEncryption", "encrypt"));
474 break;
475 }
476 }
477 break;
478 default:
479 this.ParseHelper.UnexpectedAttribute(element, attrib);
480 break;
481 }
482 }
483 else
484 {
485 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
486 }
487 }
488
489 // parse children
490 foreach (var child in element.Elements())
491 {
492 if (this.Namespace == child.Name.Namespace)
493 {
494 switch (child.Name.LocalName)
495 {
496 case "RemoteAddress":
497 if (scope != null)
498 {
499 this.Messaging.Write(FirewallErrors.IllegalRemoteAddressWithScopeAttribute(sourceLineNumbers));
500 }
501 else
502 {
503 this.ParseRemoteAddressElement(intermediate, section, child, ref remoteAddresses);
504 }
505 break;
506 case "Interface":
507 if (interfaceValue != null)
508 {
509 this.Messaging.Write(FirewallErrors.IllegalInterfaceWithInterfaceAttribute(sourceLineNumbers));
510 }
511 else
512 {
513 this.ParseInterfaceElement(intermediate, section, child, ref interfaces);
514 }
515 break;
516 case "InterfaceType":
517 if (interfaceTypeValue != null)
518 {
519 this.Messaging.Write(FirewallErrors.IllegalInterfaceTypeWithInterfaceTypeAttribute(sourceLineNumbers));
520 }
521 else
522 {
523 this.ParseInterfaceTypeElement(intermediate, section, child, ref interfaceTypes);
524 }
525 break;
526 case "LocalAddress":
527 if (localScope != null)
528 {
529 this.Messaging.Write(FirewallErrors.IllegalLocalAddressWithLocalScopeAttribute(sourceLineNumbers));
530 }
531 else
532 {
533 this.ParseLocalAddressElement(intermediate, section, child, ref localAddresses);
534 }
535 break;
536
537 default:
538 this.ParseHelper.UnexpectedElement(element, child);
539 break;
540 }
541 }
542 else
543 {
544 this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child);
545 }
546 }
547
548 if (id == null)
549 {
550 // firewall rule names are meant to be unique
551 id = this.ParseHelper.CreateIdentifier("fex", name, componentId);
552 }
553
554 // Name is required
555 if (name == null)
556 {
557 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
558 }
559
560 if (service == null)
561 {
562 service = serviceName;
563 }
564
565 // can't have both Program and File
566 if (program != null && file != null)
567 {
568 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "File", "Program"));
569 }
570
571 // 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.
572 if (edgeTraversal == FirewallConstants.NET_FW_EDGE_TRAVERSAL_TYPE_DEFER_TO_USER.ToString())
573 {
574 if (protocol != null && !(protocol == FirewallConstants.NET_FW_IP_PROTOCOL_TCP.ToString() || protocol == FirewallConstants.NET_FW_IP_PROTOCOL_UDP.ToString()))
575 {
576 this.Messaging.Write(ErrorMessages.IllegalAttributeValueWithLegalList(sourceLineNumbers, element.Name.LocalName, "Protocol", protocolValue, "tcp,udp"));
577 }
578
579 if (String.IsNullOrEmpty(fileId) && String.IsNullOrEmpty(file) && String.IsNullOrEmpty(program))
580 {
581 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Program", "EdgeTraversal", "deferToUser"));
582 }
583
584 if (port != null)
585 {
586 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "Port", "EdgeTraversal", "deferToUser"));
587 }
588
589 if (remotePort != null)
590 {
591 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "RemotePort", "EdgeTraversal", "deferToUser"));
592 }
593
594 if (localScope != null)
595 {
596 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "LocalScope", "EdgeTraversal", "deferToUser"));
597 }
598
599 if (scope != null)
600 {
601 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "Scope", "EdgeTraversal", "deferToUser"));
602 }
603
604 if (profile != null)
605 {
606 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "Profile", "EdgeTraversal", "deferToUser"));
607 }
608
609 if (service != null)
610 {
611 if (serviceName != null)
612 {
613 this.Messaging.Write(ErrorMessages.IllegalAttributeValueWhenNested(sourceLineNumbers, element.Name.LocalName, "EdgeTraversal", "deferToUser", parentElement.Name.LocalName));
614 }
615 else
616 {
617 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "Service", "EdgeTraversal", "deferToUser"));
618 }
619 }
620 }
621
622 if (!this.Messaging.EncounteredError)
623 {
624 // at this point, File attribute and File parent element are treated the same
625 if (file != null)
626 {
627 fileId = file;
628 }
629
630 var symbol = section.AddSymbol(new WixFirewallExceptionSymbol(sourceLineNumbers, id)
631 {
632 Name = name,
633 RemoteAddresses = remoteAddresses,
634 ComponentRef = componentId,
635 Description = description,
636 Direction = direction ?? FirewallConstants.NET_FW_RULE_DIR_IN,
637 Action = action ?? FirewallConstants.IntegerNotSetString,
638 EdgeTraversal = edgeTraversal ?? FirewallConstants.IntegerNotSetString,
639 Enabled = enabled ?? FirewallConstants.IntegerNotSetString,
640 Grouping = grouping,
641 IcmpTypesAndCodes = icmpTypesAndCodes,
642 Interfaces = interfaces,
643 InterfaceTypes = interfaceTypes,
644 LocalAddresses = localAddresses,
645 Port = port,
646 Profile = profile ?? FirewallConstants.IntegerNotSetString,
647 Protocol = protocol ?? FirewallConstants.IntegerNotSetString,
648 RemotePort = remotePort,
649 ServiceName = service,
650 LocalAppPackageId = localAppPackageId,
651 LocalUserAuthorizedList = localUserAuthorizedList,
652 LocalUserOwner = localUserOwner,
653 RemoteMachineAuthorizedList = remoteMachineAuthorizedList,
654 RemoteUserAuthorizedList = remoteUserAuthorizedList,
655 SecureFlags = secureFlags ?? FirewallConstants.IntegerNotSetString,
656 });
657
658 if (String.IsNullOrEmpty(protocol))
659 {
660 if (!String.IsNullOrEmpty(port) || !String.IsNullOrEmpty(remotePort))
661 {
662 symbol.Protocol = FirewallConstants.NET_FW_IP_PROTOCOL_TCP.ToString();
663 }
664 }
665
666 if (!String.IsNullOrEmpty(fileId))
667 {
668 symbol.Program = $"[#{fileId}]";
669 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.File, fileId);
670 }
671 else if (!String.IsNullOrEmpty(program))
672 {
673 symbol.Program = program;
674 }
675
676 if (attributes != CompilerConstants.IntegerNotSet)
677 {
678 symbol.Attributes = attributes;
679 }
680
681 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix5SchedFirewallExceptionsInstall", this.Context.Platform, CustomActionPlatforms.ARM64 | CustomActionPlatforms.X64 | CustomActionPlatforms.X86);
682 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix5SchedFirewallExceptionsUninstall", this.Context.Platform, CustomActionPlatforms.ARM64 | CustomActionPlatforms.X64 | CustomActionPlatforms.X86);
683 }
684 }
685
686 /// <summary>
687 /// Parses a RemoteAddress element
688 /// </summary>
689 /// <param name="element">The element to parse.</param>
690 private void ParseRemoteAddressElement(Intermediate intermediate, IntermediateSection section, XElement element, ref string remoteAddresses)
691 {
692 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
693 string address = null;
694
695 // no attributes
696 foreach (var attrib in element.Attributes())
697 {
698 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
699 {
700 switch (attrib.Name.LocalName)
701 {
702 case "Value":
703 address = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
704 break;
705 }
706 }
707 else
708 {
709 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
710 }
711 }
712
713 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
714
715 if (String.IsNullOrEmpty(address))
716 {
717 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Value"));
718 }
719 else
720 {
721 if (String.IsNullOrEmpty(remoteAddresses))
722 {
723 remoteAddresses = address;
724 }
725 else
726 {
727 remoteAddresses = String.Concat(remoteAddresses, ",", address);
728 }
729 }
730 }
731
732 /// <summary>
733 /// Parses an Interface element
734 /// </summary>
735 /// <param name="element">The element to parse.</param>
736 private void ParseInterfaceElement(Intermediate intermediate, IntermediateSection section, XElement element, ref string interfaces)
737 {
738 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
739 string name = null;
740
741 // no attributes
742 foreach (var attrib in element.Attributes())
743 {
744 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
745 {
746 switch (attrib.Name.LocalName)
747 {
748 case "Name":
749 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
750 break;
751 }
752 }
753 else
754 {
755 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
756 }
757 }
758
759 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
760
761 if (String.IsNullOrEmpty(name))
762 {
763 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
764 }
765 else
766 {
767 if (String.IsNullOrEmpty(interfaces))
768 {
769 interfaces = name;
770 }
771 else
772 {
773 interfaces = String.Concat(interfaces, FirewallConstants.FORBIDDEN_FIREWALL_CHAR, name);
774 }
775 }
776 }
777
778 /// <summary>
779 /// Parses an InterfaceType element
780 /// </summary>
781 /// <param name="element">The element to parse.</param>
782 private void ParseInterfaceTypeElement(Intermediate intermediate, IntermediateSection section, XElement element, ref string interfaceTypes)
783 {
784 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
785 string value = null;
786
787 // no attributes
788 foreach (var attrib in element.Attributes())
789 {
790 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
791 {
792 switch (attrib.Name.LocalName)
793 {
794 case "Value":
795 value = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
796 break;
797 }
798 }
799 else
800 {
801 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
802 }
803 }
804
805 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
806
807 if (String.IsNullOrEmpty(value))
808 {
809 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Value"));
810 }
811 else
812 {
813 switch (value)
814 {
815 case "remoteAccess":
816 value = "RemoteAccess";
817 break;
818 case "wireless":
819 value = "Wireless";
820 break;
821 case "lan":
822 value = "Lan";
823 break;
824 case "all":
825 value = "All";
826 break;
827
828 default:
829 if (!this.ParseHelper.ContainsProperty(value))
830 {
831 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "Value", value, "remoteAccess", "wireless", "lan", "all"));
832 value = null;
833 }
834 break;
835 }
836
837 if (String.IsNullOrEmpty(interfaceTypes))
838 {
839 interfaceTypes = value;
840 }
841 else if (interfaceTypes.Contains("All"))
842 {
843 if (value != "All")
844 {
845 this.Messaging.Write(FirewallErrors.IllegalInterfaceTypeWithInterfaceTypeAll(sourceLineNumbers));
846 }
847 }
848 else if(!String.IsNullOrEmpty(value))
849 {
850 interfaceTypes = String.Concat(interfaceTypes, ",", value);
851 }
852 }
853 }
854
855 /// <summary>
856 /// Parses a RemoteAddress element
857 /// </summary>
858 /// <param name="element">The element to parse.</param>
859 private void ParseLocalAddressElement(Intermediate intermediate, IntermediateSection section, XElement element, ref string localAddresses)
860 {
861 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
862 string address = null;
863
864 // no attributes
865 foreach (var attrib in element.Attributes())
866 {
867 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
868 {
869 switch (attrib.Name.LocalName)
870 {
871 case "Value":
872 address = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
873 break;
874 }
875 }
876 else
877 {
878 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
879 }
880 }
881
882 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
883
884 if (String.IsNullOrEmpty(address))
885 {
886 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Value"));
887 }
888 else
889 {
890 if (String.IsNullOrEmpty(localAddresses))
891 {
892 localAddresses = address;
893 }
894 else
895 {
896 localAddresses = String.Concat(localAddresses, ",", address);
897 }
898 }
899 }
900 }
901 }