From 283dd7765a7911753b0f1df60b35593a9cfe30de Mon Sep 17 00:00:00 2001 From: chris_bednarski Date: Sat, 26 Aug 2023 18:51:38 +1000 Subject: [PATCH] change firewall extension table name to Wix5FirewallException --- src/ext/Firewall/ca/firewall.cpp | 18 +- .../FirewallExtensionFixture.cs | 160 +++++++++++-- .../UsingFirewall/PackageComponents.wxs | 4 + src/ext/Firewall/wixext/FirewallCompiler.cs | 40 +++- src/ext/Firewall/wixext/FirewallDecompiler.cs | 40 ++-- .../wixext/FirewallTableDefinitions.cs | 6 +- .../wixlib/FirewallExtension_Platform.wxi | 32 +-- src/ext/caDecor.h | 10 + src/ext/caDecor.wxi | 6 + .../ProtocolRules/ProtocolRules.wixproj | 13 ++ .../ProtocolRules/product.wxs | 23 ++ .../ScopeRules/ScopeRules.wixproj | 13 ++ .../ScopeRules/product.wxs | 33 +++ .../FirewallExtensionTests.cs | 217 ++++++++++++++++++ src/wix/WixToolset.Converters/WixConverter.cs | 4 +- 15 files changed, 552 insertions(+), 67 deletions(-) create mode 100644 src/test/msi/TestData/FirewallExtensionTests/ProtocolRules/ProtocolRules.wixproj create mode 100644 src/test/msi/TestData/FirewallExtensionTests/ProtocolRules/product.wxs create mode 100644 src/test/msi/TestData/FirewallExtensionTests/ScopeRules/ScopeRules.wixproj create mode 100644 src/test/msi/TestData/FirewallExtensionTests/ScopeRules/product.wxs diff --git a/src/ext/Firewall/ca/firewall.cpp b/src/ext/Firewall/ca/firewall.cpp index 2a1ef8256..eed6f9df9 100644 --- a/src/ext/Firewall/ca/firewall.cpp +++ b/src/ext/Firewall/ca/firewall.cpp @@ -3,7 +3,7 @@ #include "precomp.h" LPCWSTR vcsFirewallExceptionQuery = - L"SELECT `Name`, `RemoteAddresses`, `Port`, `Protocol`, `Program`, `Attributes`, `Profile`, `Component_`, `Description`, `Direction` FROM `Wix4FirewallException`"; + L"SELECT `Name`, `RemoteAddresses`, `Port`, `Protocol`, `Program`, `Attributes`, `Profile`, `Component_`, `Description`, `Direction` FROM `Wix5FirewallException`"; enum eFirewallExceptionQuery { feqName = 1, feqRemoteAddresses, feqPort, feqProtocol, feqProgram, feqAttributes, feqProfile, feqComponent, feqDescription, feqDirection }; enum eFirewallExceptionTarget { fetPort = 1, fetApplication, fetUnknown }; enum eFirewallExceptionAttributes { feaIgnoreFailures = 1 }; @@ -49,15 +49,15 @@ static UINT SchedFirewallExceptions( ExitOnFailure(hr, "Failed to initialize"); // anything to do? - if (S_OK != WcaTableExists(L"Wix4FirewallException")) + if (S_OK != WcaTableExists(L"Wix5FirewallException")) { - WcaLog(LOGMSG_STANDARD, "Wix4FirewallException table doesn't exist, so there are no firewall exceptions to configure."); + WcaLog(LOGMSG_STANDARD, "Wix5FirewallException table doesn't exist, so there are no firewall exceptions to configure."); ExitFunction(); } // query and loop through all the firewall exceptions hr = WcaOpenExecuteView(vcsFirewallExceptionQuery, &hView); - ExitOnFailure(hr, "Failed to open view on Wix4FirewallException table"); + ExitOnFailure(hr, "Failed to open view on Wix5FirewallException table"); while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) { @@ -150,7 +150,7 @@ static UINT SchedFirewallExceptions( { hr = S_OK; } - ExitOnFailure(hr, "failure occured while processing Wix4FirewallException table"); + ExitOnFailure(hr, "failure occured while processing Wix5FirewallException table"); // schedule ExecFirewallExceptions if there's anything to do if (pwzCustomActionData && *pwzCustomActionData) @@ -159,16 +159,16 @@ static UINT SchedFirewallExceptions( if (WCA_TODO_INSTALL == todoSched) { - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackFirewallExceptionsInstall"), pwzCustomActionData, cFirewallExceptions * COST_FIREWALL_EXCEPTION); + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION5(L"RollbackFirewallExceptionsInstall"), pwzCustomActionData, cFirewallExceptions * COST_FIREWALL_EXCEPTION); ExitOnFailure(hr, "failed to schedule firewall install exceptions rollback"); - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"ExecFirewallExceptionsInstall"), pwzCustomActionData, cFirewallExceptions * COST_FIREWALL_EXCEPTION); + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION5(L"ExecFirewallExceptionsInstall"), pwzCustomActionData, cFirewallExceptions * COST_FIREWALL_EXCEPTION); ExitOnFailure(hr, "failed to schedule firewall install exceptions execution"); } else { - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackFirewallExceptionsUninstall"), pwzCustomActionData, cFirewallExceptions * COST_FIREWALL_EXCEPTION); + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION5(L"RollbackFirewallExceptionsUninstall"), pwzCustomActionData, cFirewallExceptions * COST_FIREWALL_EXCEPTION); ExitOnFailure(hr, "failed to schedule firewall uninstall exceptions rollback"); - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"ExecFirewallExceptionsUninstall"), pwzCustomActionData, cFirewallExceptions * COST_FIREWALL_EXCEPTION); + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION5(L"ExecFirewallExceptionsUninstall"), pwzCustomActionData, cFirewallExceptions * COST_FIREWALL_EXCEPTION); ExitOnFailure(hr, "failed to schedule firewall uninstall exceptions execution"); } } diff --git a/src/ext/Firewall/test/WixToolsetTest.Firewall/FirewallExtensionFixture.cs b/src/ext/Firewall/test/WixToolsetTest.Firewall/FirewallExtensionFixture.cs index 06a877f6a..7119e92da 100644 --- a/src/ext/Firewall/test/WixToolsetTest.Firewall/FirewallExtensionFixture.cs +++ b/src/ext/Firewall/test/WixToolsetTest.Firewall/FirewallExtensionFixture.cs @@ -18,17 +18,21 @@ public void CanBuildUsingFirewall() var folder = TestData.Get(@"TestData\UsingFirewall"); var build = new Builder(folder, typeof(FirewallExtensionFactory), new[] { folder }); - var results = build.BuildAndQuery(Build, "Wix4FirewallException", "CustomAction"); + var results = build.BuildAndQuery(Build, "Wix5FirewallException", "CustomAction"); WixAssert.CompareLineByLine(new[] { - "CustomAction:Wix4ExecFirewallExceptionsInstall_X86\t3073\tWix4FWCA_X86\tExecFirewallExceptions\t", - "CustomAction:Wix4ExecFirewallExceptionsUninstall_X86\t3073\tWix4FWCA_X86\tExecFirewallExceptions\t", - "CustomAction:Wix4RollbackFirewallExceptionsInstall_X86\t3329\tWix4FWCA_X86\tExecFirewallExceptions\t", - "CustomAction:Wix4RollbackFirewallExceptionsUninstall_X86\t3329\tWix4FWCA_X86\tExecFirewallExceptions\t", - "CustomAction:Wix4SchedFirewallExceptionsInstall_X86\t1\tWix4FWCA_X86\tSchedFirewallExceptionsInstall\t", - "CustomAction:Wix4SchedFirewallExceptionsUninstall_X86\t1\tWix4FWCA_X86\tSchedFirewallExceptionsUninstall\t", - "Wix4FirewallException:ExampleFirewall\tExampleApp\t*\t42\t6\t[#filNdJBJmq3UCUIwmXS8x21aAsvqzk]\t0\t2147483647\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tAn app-based firewall exception\t1", - "Wix4FirewallException:fex70IVsYNnbwiHQrEepmdTPKH8XYs\tExamplePort\tLocalSubnet\t42\t6\t\t0\t2147483647\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tA port-based firewall exception\t2", + "CustomAction:Wix5ExecFirewallExceptionsInstall_X86\t3073\tWix5FWCA_X86\tExecFirewallExceptions\t", + "CustomAction:Wix5ExecFirewallExceptionsUninstall_X86\t3073\tWix5FWCA_X86\tExecFirewallExceptions\t", + "CustomAction:Wix5RollbackFirewallExceptionsInstall_X86\t3329\tWix5FWCA_X86\tExecFirewallExceptions\t", + "CustomAction:Wix5RollbackFirewallExceptionsUninstall_X86\t3329\tWix5FWCA_X86\tExecFirewallExceptions\t", + "CustomAction:Wix5SchedFirewallExceptionsInstall_X86\t1\tWix5FWCA_X86\tSchedFirewallExceptionsInstall\t", + "CustomAction:Wix5SchedFirewallExceptionsUninstall_X86\t1\tWix5FWCA_X86\tSchedFirewallExceptionsUninstall\t", + "Wix5FirewallException:ExampleFirewall\tExampleApp\t*\t42\t6\t[#filNdJBJmq3UCUIwmXS8x21aAsvqzk]\t0\t2147483647\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tAn app-based firewall exception\t1", + "Wix5FirewallException:fex_ZpDsnKyHlYiA24JHzvFxm3uLZ8\tExampleDefaultGatewayScope\tDefaultGateway\t4432\t6\t\t0\t2\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tdefaultGateway scope firewall exception\t1", + "Wix5FirewallException:fex6bkfWwpiRGI.wVFx0T7W4LXIHxU\tExampleDHCPScope\tdhcp\t\t211\ttest.exe\t0\t4\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tDHCP scope firewall exception\t1", + "Wix5FirewallException:fex70IVsYNnbwiHQrEepmdTPKH8XYs\tExamplePort\tLocalSubnet\t42\t6\t\t0\t2147483647\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tA port-based firewall exception\t2", + "Wix5FirewallException:fexXxaXCXXFh.UxO_BjmZxi1B1du_Q\tExampleWINSScope\twins\t6573\t6\t\t0\t1\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tWINS scope firewall exception\t1", + "Wix5FirewallException:fexxY71H2ZBkPalv7uid1Yy4qaA_lA\tExampleDNSScope\tdns\t356\t17\t\t0\t2147483647\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tDNS scope firewall exception\t1", }, results); } @@ -38,17 +42,21 @@ public void CanBuildUsingFirewallARM64() var folder = TestData.Get(@"TestData\UsingFirewall"); var build = new Builder(folder, typeof(FirewallExtensionFactory), new[] { folder }); - var results = build.BuildAndQuery(BuildARM64, "Wix4FirewallException", "CustomAction"); + var results = build.BuildAndQuery(BuildARM64, "Wix5FirewallException", "CustomAction"); WixAssert.CompareLineByLine(new[] { - "CustomAction:Wix4ExecFirewallExceptionsInstall_A64\t3073\tWix4FWCA_A64\tExecFirewallExceptions\t", - "CustomAction:Wix4ExecFirewallExceptionsUninstall_A64\t3073\tWix4FWCA_A64\tExecFirewallExceptions\t", - "CustomAction:Wix4RollbackFirewallExceptionsInstall_A64\t3329\tWix4FWCA_A64\tExecFirewallExceptions\t", - "CustomAction:Wix4RollbackFirewallExceptionsUninstall_A64\t3329\tWix4FWCA_A64\tExecFirewallExceptions\t", - "CustomAction:Wix4SchedFirewallExceptionsInstall_A64\t1\tWix4FWCA_A64\tSchedFirewallExceptionsInstall\t", - "CustomAction:Wix4SchedFirewallExceptionsUninstall_A64\t1\tWix4FWCA_A64\tSchedFirewallExceptionsUninstall\t", - "Wix4FirewallException:ExampleFirewall\tExampleApp\t*\t42\t6\t[#filNdJBJmq3UCUIwmXS8x21aAsvqzk]\t0\t2147483647\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tAn app-based firewall exception\t1", - "Wix4FirewallException:fex70IVsYNnbwiHQrEepmdTPKH8XYs\tExamplePort\tLocalSubnet\t42\t6\t\t0\t2147483647\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tA port-based firewall exception\t2", + "CustomAction:Wix5ExecFirewallExceptionsInstall_A64\t3073\tWix5FWCA_A64\tExecFirewallExceptions\t", + "CustomAction:Wix5ExecFirewallExceptionsUninstall_A64\t3073\tWix5FWCA_A64\tExecFirewallExceptions\t", + "CustomAction:Wix5RollbackFirewallExceptionsInstall_A64\t3329\tWix5FWCA_A64\tExecFirewallExceptions\t", + "CustomAction:Wix5RollbackFirewallExceptionsUninstall_A64\t3329\tWix5FWCA_A64\tExecFirewallExceptions\t", + "CustomAction:Wix5SchedFirewallExceptionsInstall_A64\t1\tWix5FWCA_A64\tSchedFirewallExceptionsInstall\t", + "CustomAction:Wix5SchedFirewallExceptionsUninstall_A64\t1\tWix5FWCA_A64\tSchedFirewallExceptionsUninstall\t", + "Wix5FirewallException:ExampleFirewall\tExampleApp\t*\t42\t6\t[#filNdJBJmq3UCUIwmXS8x21aAsvqzk]\t0\t2147483647\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tAn app-based firewall exception\t1", + "Wix5FirewallException:fex_ZpDsnKyHlYiA24JHzvFxm3uLZ8\tExampleDefaultGatewayScope\tDefaultGateway\t4432\t6\t\t0\t2\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tdefaultGateway scope firewall exception\t1", + "Wix5FirewallException:fex6bkfWwpiRGI.wVFx0T7W4LXIHxU\tExampleDHCPScope\tdhcp\t\t211\ttest.exe\t0\t4\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tDHCP scope firewall exception\t1", + "Wix5FirewallException:fex70IVsYNnbwiHQrEepmdTPKH8XYs\tExamplePort\tLocalSubnet\t42\t6\t\t0\t2147483647\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tA port-based firewall exception\t2", + "Wix5FirewallException:fexXxaXCXXFh.UxO_BjmZxi1B1du_Q\tExampleWINSScope\twins\t6573\t6\t\t0\t1\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tWINS scope firewall exception\t1", + "Wix5FirewallException:fexxY71H2ZBkPalv7uid1Yy4qaA_lA\tExampleDNSScope\tdns\t356\t17\t\t0\t2147483647\tfilNdJBJmq3UCUIwmXS8x21aAsvqzk\tDNS scope firewall exception\t1", }, results); } @@ -71,8 +79,17 @@ public void CanRoundtripFirewallExceptions() { "FirewallException", "FirewallException", + "FirewallException", + "FirewallException", + "FirewallException", + "FirewallException", }, actual.Select(a => a.Name).ToArray()); + } + [Fact] + public void RoundtripAttributesAreCorrectForApp() + { + var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "ExampleApp"); WixAssert.CompareLineByLine(new[] { "Id=ExampleFirewall", @@ -85,8 +102,13 @@ public void CanRoundtripFirewallExceptions() "Description=An app-based firewall exception", "Outbound=no", "xmlns=http://wixtoolset.org/schemas/v4/wxs/firewall", - }, actual[0].Attributes); + }, actual.Attributes); + } + [Fact] + public void RoundtripAttributesAreCorrectForPort() + { + var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "ExamplePort"); WixAssert.CompareLineByLine(new[] { "Id=fex70IVsYNnbwiHQrEepmdTPKH8XYs", @@ -98,7 +120,79 @@ public void CanRoundtripFirewallExceptions() "Description=A port-based firewall exception", "Outbound=yes", "xmlns=http://wixtoolset.org/schemas/v4/wxs/firewall", - }, actual[1].Attributes); + }, actual.Attributes); + } + + [Fact] + public void RoundtripAttributesAreCorrectForDNSScope() + { + var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "ExampleDNSScope"); + WixAssert.CompareLineByLine(new[] + { + "Id=fexxY71H2ZBkPalv7uid1Yy4qaA_lA", + "Name=ExampleDNSScope", + "Scope=DNS", + "Port=356", + "Protocol=udp", + "Profile=all", + "Description=DNS scope firewall exception", + "Outbound=no", + "xmlns=http://wixtoolset.org/schemas/v4/wxs/firewall", + }, actual.Attributes); + } + + [Fact] + public void RoundtripAttributesAreCorrectForDHCPScope() + { + var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "ExampleDHCPScope"); + WixAssert.CompareLineByLine(new[] + { + "Id=fex6bkfWwpiRGI.wVFx0T7W4LXIHxU", + "Name=ExampleDHCPScope", + "Scope=DHCP", + "Protocol=211", + "Program=test.exe", + "Profile=public", + "Description=DHCP scope firewall exception", + "Outbound=no", + "xmlns=http://wixtoolset.org/schemas/v4/wxs/firewall" + }, actual.Attributes); + } + + [Fact] + public void RoundtripAttributesAreCorrectForWINSScope() + { + var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "ExampleWINSScope"); + WixAssert.CompareLineByLine(new[] + { + "Id=fexXxaXCXXFh.UxO_BjmZxi1B1du_Q", + "Name=ExampleWINSScope", + "Scope=WINS", + "Port=6573", + "Protocol=tcp", + "Profile=domain", + "Description=WINS scope firewall exception", + "Outbound=no", + "xmlns=http://wixtoolset.org/schemas/v4/wxs/firewall", + }, actual.Attributes); + } + + [Fact] + public void RoundtripAttributesAreCorrectForDefaultGatewayScope() + { + var actual = BuildAndDecompileAndBuild("http://wixtoolset.org/schemas/v4/wxs/firewall", "ExampleDefaultGatewayScope"); + WixAssert.CompareLineByLine(new[] + { + "Id=fex_ZpDsnKyHlYiA24JHzvFxm3uLZ8", + "Name=ExampleDefaultGatewayScope", + "Scope=defaultGateway", + "Port=4432", + "Protocol=tcp", + "Profile=private", + "Description=defaultGateway scope firewall exception", + "Outbound=no", + "xmlns=http://wixtoolset.org/schemas/v4/wxs/firewall", + }, actual.Attributes); } private static void Build(string[] args) @@ -122,5 +216,31 @@ private static void Decompile(string[] args) var result = WixRunner.Execute(args); result.AssertSuccess(); } + class AttributeVerifier + { + public string Name { get; set; } + public string[] Attributes { get; set; } + } + + private static AttributeVerifier BuildAndDecompileAndBuild(string nameSpace, string ruleName) + { + var folder = TestData.Get(@"TestData", "UsingFirewall"); + var build = new Builder(folder, typeof(FirewallExtensionFactory), new[] { folder }); + var output = Path.Combine(folder, $"Firewall{ruleName}.xml"); + + build.BuildAndDecompileAndBuild(Build, Decompile, output); + + var doc = XDocument.Load(output); + var actual = doc.Descendants() + .Where(e => e.Name.Namespace == nameSpace) + .Select(fe => new AttributeVerifier + { + Name = fe.Attributes().Single(a => a.Name.LocalName == "Name").Value, + Attributes = fe.Attributes().Select(a => $"{a.Name.LocalName}={a.Value}").ToArray() + }) + .Single(av => av.Name == ruleName); + + return actual; + } } } diff --git a/src/ext/Firewall/test/WixToolsetTest.Firewall/TestData/UsingFirewall/PackageComponents.wxs b/src/ext/Firewall/test/WixToolsetTest.Firewall/TestData/UsingFirewall/PackageComponents.wxs index c712d8959..957aa6427 100644 --- a/src/ext/Firewall/test/WixToolsetTest.Firewall/TestData/UsingFirewall/PackageComponents.wxs +++ b/src/ext/Firewall/test/WixToolsetTest.Firewall/TestData/UsingFirewall/PackageComponents.wxs @@ -12,6 +12,10 @@ + + + + diff --git a/src/ext/Firewall/wixext/FirewallCompiler.cs b/src/ext/Firewall/wixext/FirewallCompiler.cs index 19ee0b6dc..ed49ba9c4 100644 --- a/src/ext/Firewall/wixext/FirewallCompiler.cs +++ b/src/ext/Firewall/wixext/FirewallCompiler.cs @@ -135,7 +135,12 @@ private void ParseFirewallExceptionElement(Intermediate intermediate, Intermedia protocol = FirewallConstants.NET_FW_IP_PROTOCOL_UDP; break; default: - this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "Protocol", protocolValue, "tcp", "udp")); + int parsedProtocol; + if (!Int32.TryParse(protocolValue, out parsedProtocol) || parsedProtocol > 255 || parsedProtocol < 0) + { + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "Protocol", protocolValue, "tcp", "udp", "0-255")); + } + protocol = parsedProtocol; break; } break; @@ -149,8 +154,20 @@ private void ParseFirewallExceptionElement(Intermediate intermediate, Intermedia case "localSubnet": remoteAddresses = "LocalSubnet"; break; + case "DNS": + remoteAddresses = "dns"; + break; + case "DHCP": + remoteAddresses = "dhcp"; + break; + case "WINS": + remoteAddresses = "wins"; + break; + case "defaultGateway": + remoteAddresses = "DefaultGateway"; + break; default: - this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "Scope", scope, "any", "localSubnet")); + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "Scope", scope, "any", "localSubnet", "DNS", "DHCP", "WINS", "defaultGateway")); break; } break; @@ -251,6 +268,21 @@ private void ParseFirewallExceptionElement(Intermediate intermediate, Intermedia this.Messaging.Write(FirewallErrors.NoExceptionSpecified(sourceLineNumbers)); } + // Ports can only be specified if the protocol is TCP or UDP. + if (!String.IsNullOrEmpty(port) && protocol.HasValue) + { + switch(protocol.Value) + { + case FirewallConstants.NET_FW_IP_PROTOCOL_TCP: + case FirewallConstants.NET_FW_IP_PROTOCOL_UDP: + break; + + default: + this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "Port", "Protocol", protocol.Value.ToString())); + break; + } + } + if (!this.Messaging.EncounteredError) { // at this point, File attribute and File parent element are treated the same @@ -300,8 +332,8 @@ private void ParseFirewallExceptionElement(Intermediate intermediate, Intermedia symbol.Attributes = attributes; } - this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4SchedFirewallExceptionsInstall", this.Context.Platform, CustomActionPlatforms.ARM64 | CustomActionPlatforms.X64 | CustomActionPlatforms.X86); - this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4SchedFirewallExceptionsUninstall", this.Context.Platform, CustomActionPlatforms.ARM64 | CustomActionPlatforms.X64 | CustomActionPlatforms.X86); + this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix5SchedFirewallExceptionsInstall", this.Context.Platform, CustomActionPlatforms.ARM64 | CustomActionPlatforms.X64 | CustomActionPlatforms.X86); + this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix5SchedFirewallExceptionsUninstall", this.Context.Platform, CustomActionPlatforms.ARM64 | CustomActionPlatforms.X64 | CustomActionPlatforms.X86); } } diff --git a/src/ext/Firewall/wixext/FirewallDecompiler.cs b/src/ext/Firewall/wixext/FirewallDecompiler.cs index 69f2c3f4d..9ddd8a9a3 100644 --- a/src/ext/Firewall/wixext/FirewallDecompiler.cs +++ b/src/ext/Firewall/wixext/FirewallDecompiler.cs @@ -32,7 +32,7 @@ public override bool TryDecompileTable(Table table) { switch (table.Name) { - case "Wix4FirewallException": + case "Wix5FirewallException": this.DecompileWixFirewallExceptionTable(table); break; default: @@ -69,18 +69,29 @@ private void DecompileWixFirewallExceptionTable(Table table) string[] addresses = ((string)row[2]).Split(','); if (addresses.Length == 1) { - // special-case the Scope attribute values - if (addresses[0] == "*") + switch(addresses[0]) { - firewallException.Add(new XAttribute("Scope", "any")); - } - else if (addresses[0] == "LocalSubnet") - { - firewallException.Add(new XAttribute("Scope", "localSubnet")); - } - else - { - FirewallDecompiler.AddRemoteAddress(firewallException, addresses[0]); + case "*": + firewallException.Add(new XAttribute("Scope", "any")); + break; + case "LocalSubnet": + firewallException.Add(new XAttribute("Scope", "localSubnet")); + break; + case "dns": + firewallException.Add(new XAttribute("Scope", "DNS")); + break; + case "dhcp": + firewallException.Add(new XAttribute("Scope", "DHCP")); + break; + case "wins": + firewallException.Add(new XAttribute("Scope", "WINS")); + break; + case "DefaultGateway": + firewallException.Add(new XAttribute("Scope", "defaultGateway")); + break; + default: + FirewallDecompiler.AddRemoteAddress(firewallException, addresses[0]); + break; } } else @@ -107,6 +118,9 @@ private void DecompileWixFirewallExceptionTable(Table table) case FirewallConstants.NET_FW_IP_PROTOCOL_UDP: firewallException.Add(new XAttribute("Protocol", "udp")); break; + default: + firewallException.Add(new XAttribute("Protocol", row[4])); + break; } } @@ -183,7 +197,7 @@ private static XAttribute AttributeIfNotNull(string name, bool value) /// Collection of all tables. private void FinalizeFirewallExceptionTable(TableIndexedCollection tables) { - if (tables.TryGetTable("Wix4FirewallException", out var firewallExceptionTable)) + if (tables.TryGetTable("Wix5FirewallException", out var firewallExceptionTable)) { foreach (var row in firewallExceptionTable.Rows) { diff --git a/src/ext/Firewall/wixext/FirewallTableDefinitions.cs b/src/ext/Firewall/wixext/FirewallTableDefinitions.cs index 04918f5f0..26dedbf1d 100644 --- a/src/ext/Firewall/wixext/FirewallTableDefinitions.cs +++ b/src/ext/Firewall/wixext/FirewallTableDefinitions.cs @@ -7,15 +7,15 @@ namespace WixToolset.Firewall public static class FirewallTableDefinitions { public static readonly TableDefinition WixFirewallException = new TableDefinition( - "Wix4FirewallException", + "Wix5FirewallException", FirewallSymbolDefinitions.WixFirewallException, new[] { - new ColumnDefinition("Wix4FirewallException", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "The primary key, a non-localized token.", modularizeType: ColumnModularizeType.Column), + new ColumnDefinition("Wix5FirewallException", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "The primary key, a non-localized token.", modularizeType: ColumnModularizeType.Column), new ColumnDefinition("Name", ColumnType.Localized, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "Localizable display name.", modularizeType: ColumnModularizeType.Property), new ColumnDefinition("RemoteAddresses", ColumnType.String, 0, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "Remote address to accept incoming connections from.", modularizeType: ColumnModularizeType.Property), new ColumnDefinition("Port", ColumnType.String, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, minValue: 1, description: "Port number.", modularizeType: ColumnModularizeType.Property), - new ColumnDefinition("Protocol", ColumnType.Number, 1, primaryKey: false, nullable: true, ColumnCategory.Integer, minValue: 6, maxValue: 17, description: "Protocol (6=TCP; 17=UDP)."), + 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"), new ColumnDefinition("Program", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "Exception for a program (formatted path name).", modularizeType: ColumnModularizeType.Property), new ColumnDefinition("Attributes", ColumnType.Number, 4, primaryKey: false, nullable: true, ColumnCategory.Unknown, description: "Vital=1"), 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)."), diff --git a/src/ext/Firewall/wixlib/FirewallExtension_Platform.wxi b/src/ext/Firewall/wixlib/FirewallExtension_Platform.wxi index ae02bcd0b..736a54b08 100644 --- a/src/ext/Firewall/wixlib/FirewallExtension_Platform.wxi +++ b/src/ext/Firewall/wixlib/FirewallExtension_Platform.wxi @@ -6,32 +6,32 @@ - - - - - - + + + + + + - - - - - - + + + + + + - - + + - + diff --git a/src/ext/caDecor.h b/src/ext/caDecor.h index da274650f..060032cf8 100644 --- a/src/ext/caDecor.h +++ b/src/ext/caDecor.h @@ -11,3 +11,13 @@ #else #define CUSTOM_ACTION_DECORATION(f) L"Wix4" f L"_X86" #endif + +#if defined(_M_ARM64) +#define CUSTOM_ACTION_DECORATION5(f) L"Wix5" f L"_A64" +#elif defined(_M_AMD64) +#define CUSTOM_ACTION_DECORATION5(f) L"Wix5" f L"_X64" +#elif defined(_M_ARM) +#define CUSTOM_ACTION_DECORATION5(f) L"Wix5" f L"_ARM" +#else +#define CUSTOM_ACTION_DECORATION5(f) L"Wix5" f L"_X86" +#endif diff --git a/src/ext/caDecor.wxi b/src/ext/caDecor.wxi index b17115183..256d7586b 100644 --- a/src/ext/caDecor.wxi +++ b/src/ext/caDecor.wxi @@ -8,6 +8,12 @@ + + + + + + diff --git a/src/test/msi/TestData/FirewallExtensionTests/ProtocolRules/ProtocolRules.wixproj b/src/test/msi/TestData/FirewallExtensionTests/ProtocolRules/ProtocolRules.wixproj new file mode 100644 index 000000000..b1770b0f4 --- /dev/null +++ b/src/test/msi/TestData/FirewallExtensionTests/ProtocolRules/ProtocolRules.wixproj @@ -0,0 +1,13 @@ + + + + {4D188568-1CCF-4EEE-BC27-17C3DCC83E58} + true + + + + + + + + \ No newline at end of file diff --git a/src/test/msi/TestData/FirewallExtensionTests/ProtocolRules/product.wxs b/src/test/msi/TestData/FirewallExtensionTests/ProtocolRules/product.wxs new file mode 100644 index 000000000..6a28ad0ae --- /dev/null +++ b/src/test/msi/TestData/FirewallExtensionTests/ProtocolRules/product.wxs @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + diff --git a/src/test/msi/TestData/FirewallExtensionTests/ScopeRules/ScopeRules.wixproj b/src/test/msi/TestData/FirewallExtensionTests/ScopeRules/ScopeRules.wixproj new file mode 100644 index 000000000..b1770b0f4 --- /dev/null +++ b/src/test/msi/TestData/FirewallExtensionTests/ScopeRules/ScopeRules.wixproj @@ -0,0 +1,13 @@ + + + + {4D188568-1CCF-4EEE-BC27-17C3DCC83E58} + true + + + + + + + + \ No newline at end of file diff --git a/src/test/msi/TestData/FirewallExtensionTests/ScopeRules/product.wxs b/src/test/msi/TestData/FirewallExtensionTests/ScopeRules/product.wxs new file mode 100644 index 000000000..776c86750 --- /dev/null +++ b/src/test/msi/TestData/FirewallExtensionTests/ScopeRules/product.wxs @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/msi/WixToolsetTest.MsiE2E/FirewallExtensionTests.cs b/src/test/msi/WixToolsetTest.MsiE2E/FirewallExtensionTests.cs index 4106cd724..ce55aa142 100644 --- a/src/test/msi/WixToolsetTest.MsiE2E/FirewallExtensionTests.cs +++ b/src/test/msi/WixToolsetTest.MsiE2E/FirewallExtensionTests.cs @@ -315,5 +315,222 @@ public void SucceedWhenIgnoreOnFailureIsSet() var log2 = product.UninstallProduct(MSIExec.MSIExecReturnCode.SUCCESS, "NORULENAME=1"); Assert.True(LogVerifier.MessageInLogFile(log2, "failed to remove firewall rule")); } + + [RuntimeFact] + public void VarietyOfProtocolValuesCanBeUsed() + { + var product = this.CreatePackageInstaller("ProtocolRules"); + product.InstallProduct(MSIExec.MSIExecReturnCode.SUCCESS); + + var expected1 = new RuleDetails("WiXToolset401 Test - 0009") + { + Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW, + Description = "WiX Toolset firewall exception rule integration test - protocol TCP", + Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN, + EdgeTraversal = false, + EdgeTraversalOptions = 0, + Enabled = true, + InterfaceTypes = "All", + LocalAddresses = "*", + Profiles = Int32.MaxValue, + Protocol = 6, + RemoteAddresses = "*", + SecureFlags = 0, + LocalPorts = "900", + RemotePorts = "*", + }; + + Verifier.VerifyFirewallRule("WiXToolset401 Test - 0009", expected1); + + + var expected2 = new RuleDetails("WiXToolset401 Test - 0010") + { + Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW, + Description = "WiX Toolset firewall exception rule integration test - protocol UDP", + Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN, + EdgeTraversal = false, + EdgeTraversalOptions = 0, + Enabled = true, + InterfaceTypes = "All", + LocalAddresses = "*", + Profiles = Int32.MaxValue, + Protocol = 17, + RemoteAddresses = "*", + SecureFlags = 0, + LocalPorts = "1000", + RemotePorts = "*", + }; + + Verifier.VerifyFirewallRule("WiXToolset401 Test - 0010", expected2); + + + var expected3 = new RuleDetails("WiXToolset401 Test - 0011") + { + Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW, + ApplicationName = "test.exe", + Description = "WiX Toolset firewall exception rule integration test - ports can only be specified if protocol is TCP or UDP", + Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN, + EdgeTraversal = true, + EdgeTraversalOptions = 1, + Enabled = true, + InterfaceTypes = "All", + LocalAddresses = "*", + Profiles = Int32.MaxValue, + Protocol = 134, + RemoteAddresses = "*", + SecureFlags = 0, + }; + + Verifier.VerifyFirewallRule("WiXToolset401 Test - 0011", expected3); + + product.UninstallProduct(MSIExec.MSIExecReturnCode.SUCCESS); + + // verify the firewall exceptions have been removed. + Assert.False(Verifier.FirewallRuleExists("WiXToolset401 Test - 0009")); + Assert.False(Verifier.FirewallRuleExists("WiXToolset401 Test - 0010")); + Assert.False(Verifier.FirewallRuleExists("WiXToolset401 Test - 0011")); + } + + [RuntimeFact] + public void FullSetOfScopeValuesCanBeUsed() + { + var product = this.CreatePackageInstaller("ScopeRules"); + product.InstallProduct(MSIExec.MSIExecReturnCode.SUCCESS); + + var expected1 = new RuleDetails("WiXToolset401 Test - 0012") + { + Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW, + Description = "WiX Toolset firewall exception rule integration test - scope any", + Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN, + EdgeTraversal = false, + EdgeTraversalOptions = 0, + Enabled = true, + InterfaceTypes = "All", + LocalAddresses = "*", + Profiles = Int32.MaxValue, + Protocol = 6, + RemoteAddresses = "*", + SecureFlags = 0, + LocalPorts = "1200", + RemotePorts = "*", + }; + + Verifier.VerifyFirewallRule("WiXToolset401 Test - 0012", expected1); + + + var expected2 = new RuleDetails("WiXToolset401 Test - 0013") + { + Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW, + Description = "WiX Toolset firewall exception rule integration test - scope local subnet", + Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN, + EdgeTraversal = false, + EdgeTraversalOptions = 0, + Enabled = true, + InterfaceTypes = "All", + LocalAddresses = "*", + Profiles = Int32.MaxValue, + Protocol = 6, + RemoteAddresses = "LocalSubnet", + SecureFlags = 0, + LocalPorts = "1300", + RemotePorts = "*", + }; + + Verifier.VerifyFirewallRule("WiXToolset401 Test - 0013", expected2); + + + var expected3 = new RuleDetails("WiXToolset401 Test - 0014") + { + Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW, + Description = "WiX Toolset firewall exception rule integration test - scope DNS", + Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN, + EdgeTraversal = false, + EdgeTraversalOptions = 0, + Enabled = true, + InterfaceTypes = "All", + LocalAddresses = "*", + Profiles = Int32.MaxValue, + Protocol = 6, + RemoteAddresses = "DNS", + SecureFlags = 0, + LocalPorts = "1400", + RemotePorts = "*", + }; + + Verifier.VerifyFirewallRule("WiXToolset401 Test - 0014", expected3); + + + var expected4 = new RuleDetails("WiXToolset401 Test - 0015") + { + Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW, + Description = "WiX Toolset firewall exception rule integration test - scope DHCP", + Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN, + EdgeTraversal = false, + EdgeTraversalOptions = 0, + Enabled = true, + InterfaceTypes = "All", + LocalAddresses = "*", + Profiles = Int32.MaxValue, + Protocol = 6, + RemoteAddresses = "DHCP", + SecureFlags = 0, + LocalPorts = "1500", + RemotePorts = "*", + }; + + Verifier.VerifyFirewallRule("WiXToolset401 Test - 0015", expected4); + + + var expected5 = new RuleDetails("WiXToolset401 Test - 0016") + { + Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW, + Description = "WiX Toolset firewall exception rule integration test - scope WINS", + Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN, + EdgeTraversal = false, + EdgeTraversalOptions = 0, + Enabled = true, + InterfaceTypes = "All", + LocalAddresses = "*", + Profiles = Int32.MaxValue, + Protocol = 6, + RemoteAddresses = "WINS", + SecureFlags = 0, + LocalPorts = "1600", + RemotePorts = "*", + }; + + Verifier.VerifyFirewallRule("WiXToolset401 Test - 0016", expected5); + + + var expected6 = new RuleDetails("WiXToolset401 Test - 0017") + { + Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW, + Description = "WiX Toolset firewall exception rule integration test - scope default gateway", + Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN, + EdgeTraversal = false, + EdgeTraversalOptions = 0, + Enabled = true, + InterfaceTypes = "All", + LocalAddresses = "*", + Profiles = Int32.MaxValue, + Protocol = 6, + RemoteAddresses = "DefaultGateway", + SecureFlags = 0, + LocalPorts = "1700", + RemotePorts = "*", + }; + + Verifier.VerifyFirewallRule("WiXToolset401 Test - 0017", expected6); + + product.UninstallProduct(MSIExec.MSIExecReturnCode.SUCCESS); + + // verify the firewall exceptions have been removed. + Assert.False(Verifier.FirewallRuleExists("WiXToolset401 Test - 0012")); + Assert.False(Verifier.FirewallRuleExists("WiXToolset401 Test - 0013")); + Assert.False(Verifier.FirewallRuleExists("WiXToolset401 Test - 0014")); + Assert.False(Verifier.FirewallRuleExists("WiXToolset401 Test - 0015")); + Assert.False(Verifier.FirewallRuleExists("WiXToolset401 Test - 0016")); + Assert.False(Verifier.FirewallRuleExists("WiXToolset401 Test - 0017")); + } } } diff --git a/src/wix/WixToolset.Converters/WixConverter.cs b/src/wix/WixToolset.Converters/WixConverter.cs index f3675ecc6..178b90bee 100644 --- a/src/wix/WixToolset.Converters/WixConverter.cs +++ b/src/wix/WixToolset.Converters/WixConverter.cs @@ -205,8 +205,8 @@ public sealed class WixConverter { "WixDependencyRequire", "Wix4DependencyRequire_" }, { "WixDependencyCheck", "Wix4DependencyCheck_" }, { "WixQueryDirectXCaps", "Wix4QueryDirectXCaps_" }, - { "WixSchedFirewallExceptionsUninstall", "Wix4SchedFirewallExceptionsUninstall_" }, - { "WixSchedFirewallExceptionsInstall", "Wix4SchedFirewallExceptionsInstall_" }, + { "WixSchedFirewallExceptionsUninstall", "Wix5SchedFirewallExceptionsUninstall_" }, + { "WixSchedFirewallExceptionsInstall", "Wix5SchedFirewallExceptionsInstall_" }, { "WixSchedHttpUrlReservationsUninstall", "Wix4SchedHttpUrlReservationsUninstall_" }, { "WixSchedHttpUrlReservationsInstall", "Wix4SchedHttpUrlReservationsInstall_" }, { "ConfigureIIs", "Wix4ConfigureIIs_" },