From 2d457b5d433292b2be3b5361ddf08a2865b99440 Mon Sep 17 00:00:00 2001 From: petrsnd Date: Fri, 14 Mar 2025 16:31:31 -0600 Subject: [PATCH 01/13] Add a PortableDns project to Kerberos.NET --- .editorconfig | 3 ++ .../Kerberos.NET.PortableDns.csproj | 15 ++++++ Kerberos.NET.PortableDns/PortableDnsClient.cs | 51 +++++++++++++++++++ .../PortableDnsImplementation.cs | 51 +++++++++++++++++++ Kerberos.NET.sln | 11 +++- 5 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 Kerberos.NET.PortableDns/Kerberos.NET.PortableDns.csproj create mode 100644 Kerberos.NET.PortableDns/PortableDnsClient.cs create mode 100644 Kerberos.NET.PortableDns/PortableDnsImplementation.cs diff --git a/.editorconfig b/.editorconfig index 7c5c5e2c..ec2660d3 100644 --- a/.editorconfig +++ b/.editorconfig @@ -58,6 +58,9 @@ end_of_line = crlf [*.cs] +[*.generated.cs] +generated_code = true + # IDE0063: Use simple 'using' statement csharp_prefer_simple_using_statement = true:silent diff --git a/Kerberos.NET.PortableDns/Kerberos.NET.PortableDns.csproj b/Kerberos.NET.PortableDns/Kerberos.NET.PortableDns.csproj new file mode 100644 index 00000000..308a1e7a --- /dev/null +++ b/Kerberos.NET.PortableDns/Kerberos.NET.PortableDns.csproj @@ -0,0 +1,15 @@ + + + + netstandard2.0 + + + + + + + + + + + diff --git a/Kerberos.NET.PortableDns/PortableDnsClient.cs b/Kerberos.NET.PortableDns/PortableDnsClient.cs new file mode 100644 index 00000000..17a90b75 --- /dev/null +++ b/Kerberos.NET.PortableDns/PortableDnsClient.cs @@ -0,0 +1,51 @@ +using DnsClient; +using System.Linq; +using System.Net; + +namespace Kerberos.NET.PortableDns +{ + public static class PortableDnsClient + { + public static void Configure() + { + PortableDnsImplementation.Options = new LookupClientOptions(); + } + + public static void Configure(params NameServer[] nameServers) + { + PortableDnsImplementation.Options = new LookupClientOptions(nameServers); + } + + public static void Configure(params IPEndPoint[] nameServers) + { + PortableDnsImplementation.Options = new LookupClientOptions(nameServers); + } + + public static void Configure(params IPAddress[] nameServers) + { + PortableDnsImplementation.Options = new LookupClientOptions(nameServers); + } + + public static void Configure(params string[] nameServers) + { + PortableDnsImplementation.Options = new LookupClientOptions(nameServers.Select(n => { + var parts = n.Split(':'); + IPAddress address; + switch (parts.Length) + { + case 1: + address = IPAddress.Parse(parts[0]); + return new IPEndPoint(address, 53); + case 2: + address = IPAddress.Parse(parts[0]); + var port = int.Parse(parts[1]); + return new IPEndPoint(address, port); + default: + throw new System.FormatException($"{n} is not in the correct format 'IPaddress:Port'"); + } + }).ToArray()); + } + + public static LookupClientOptions Options => PortableDnsImplementation.Options; + } +} diff --git a/Kerberos.NET.PortableDns/PortableDnsImplementation.cs b/Kerberos.NET.PortableDns/PortableDnsImplementation.cs new file mode 100644 index 00000000..f2c5f9cb --- /dev/null +++ b/Kerberos.NET.PortableDns/PortableDnsImplementation.cs @@ -0,0 +1,51 @@ +using DnsClient; +using Kerberos.NET.Dns; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Kerberos.NET.PortableDns +{ + internal class PortableDnsImplementation : IKerberosDnsQuery + { + static PortableDnsImplementation() + { + DnsQuery.RegisterImplementation(new PortableDnsImplementation()); + } + + public static LookupClientOptions Options { get; set; } = new LookupClientOptions(); + + private static LookupClient Create() + { + return new LookupClient(Options); + } + + public async Task> Query(string query, DnsRecordType type) + { + var client = Create(); + var response = await client.QueryAsync(query, (QueryType)type); + var srvRecords = response.Answers.SrvRecords().Select(a => new DnsRecord + { + Name = a.DomainName, + Port = a.Port, + Priority = a.Priority, + Target = a.Target, + TimeToLive = a.TimeToLive, + Type = DnsRecordType.SRV, + Weight = a.Weight + }).ToList(); + + var merged = srvRecords.GroupBy(r => r.Name); + + foreach (var srv in srvRecords) + { + var c1 = merged.Where(m => m.Key.Equals(srv.Target, StringComparison.InvariantCultureIgnoreCase)); + var canon = c1.SelectMany(r => r); + srv.Canonical = canon.ToList(); + } + + return srvRecords; + } + } +} diff --git a/Kerberos.NET.sln b/Kerberos.NET.sln index edae1732..01e7acff 100644 --- a/Kerberos.NET.sln +++ b/Kerberos.NET.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29006.145 +# Visual Studio Version 17 +VisualStudioVersion = 17.11.35327.3 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kerberos.NET", "Kerberos.NET\Kerberos.NET.csproj", "{3066D890-0544-4E13-95FD-1DDCC72FEDA1}" EndProject @@ -29,6 +29,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Client Tools", "Client Tool EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bruce", "Bruce\Bruce.csproj", "{D12B0644-0D57-45ED-AA0A-AB18D593CCA3}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kerberos.NET.PortableDns", "Kerberos.NET.PortableDns\Kerberos.NET.PortableDns.csproj", "{3085F7D7-B384-4EB6-B5F4-CAEDC7C1C0E6}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -55,6 +57,10 @@ Global {D12B0644-0D57-45ED-AA0A-AB18D593CCA3}.Debug|Any CPU.Build.0 = Debug|Any CPU {D12B0644-0D57-45ED-AA0A-AB18D593CCA3}.Release|Any CPU.ActiveCfg = Release|Any CPU {D12B0644-0D57-45ED-AA0A-AB18D593CCA3}.Release|Any CPU.Build.0 = Release|Any CPU + {3085F7D7-B384-4EB6-B5F4-CAEDC7C1C0E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3085F7D7-B384-4EB6-B5F4-CAEDC7C1C0E6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3085F7D7-B384-4EB6-B5F4-CAEDC7C1C0E6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3085F7D7-B384-4EB6-B5F4-CAEDC7C1C0E6}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -65,6 +71,7 @@ Global {046122A3-9C6F-42E8-A21E-E4F2CD4DBCF8} = {8BD43321-3C92-4D6F-B965-783F2CC4CEE1} {5115DFE1-AD08-4AF5-B88C-F436744D7A3A} = {8F0C1D56-CBBB-4B8B-81D1-5D1544AD5C72} {D12B0644-0D57-45ED-AA0A-AB18D593CCA3} = {8BD43321-3C92-4D6F-B965-783F2CC4CEE1} + {3085F7D7-B384-4EB6-B5F4-CAEDC7C1C0E6} = {E3EE549C-8245-45E7-A964-E38C78DC9FD3} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {17150968-CFF9-4183-989D-C93E19033096} From c15e8baad455faeed60698ef650a0c908ee242dd Mon Sep 17 00:00:00 2001 From: petrsnd Date: Fri, 14 Mar 2025 16:31:50 -0600 Subject: [PATCH 02/13] Refactor Bruce to use PortableDns project on non-Windows platforms --- Bruce/Bruce.csproj | 4 +- Bruce/Dns/PlatformIndependentDnsClient.cs | 50 ----------------------- Bruce/Program.cs | 10 +++-- 3 files changed, 8 insertions(+), 56 deletions(-) delete mode 100644 Bruce/Dns/PlatformIndependentDnsClient.cs diff --git a/Bruce/Bruce.csproj b/Bruce/Bruce.csproj index 8a795643..db707155 100644 --- a/Bruce/Bruce.csproj +++ b/Bruce/Bruce.csproj @@ -1,4 +1,4 @@ - + Exe @@ -33,11 +33,11 @@ - + diff --git a/Bruce/Dns/PlatformIndependentDnsClient.cs b/Bruce/Dns/PlatformIndependentDnsClient.cs deleted file mode 100644 index 765b3448..00000000 --- a/Bruce/Dns/PlatformIndependentDnsClient.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using DnsClient; -using Kerberos.NET.Dns; - -namespace Kerberos.NET.CommandLine.Dns -{ - internal class PlatformIndependentDnsClient : IKerberosDnsQuery - { - private static readonly WindowsDnsQuery WindowsDns = new WindowsDnsQuery(); - - public async Task> Query(string query, DnsRecordType type) - { - if (WindowsDns.IsSupported) - { - return await WindowsDns.Query(query, type); - } - - var client = new LookupClient(); - - var response = await client.QueryAsync(query, (QueryType)type); - - var srvRecords = response.Answers.SrvRecords().Select(a => new DnsRecord - { - Name = a.DomainName, - Port = a.Port, - Priority = a.Priority, - Target = a.Target, - TimeToLive = a.TimeToLive, - Type = DnsRecordType.SRV, - Weight = a.Weight - }).ToList(); - - var merged = srvRecords.GroupBy(r => r.Name); - - foreach (var srv in srvRecords) - { - var c1 = merged.Where(m => m.Key.Equals(srv.Target, StringComparison.InvariantCultureIgnoreCase)); - - var canon = c1.SelectMany(r => r); - - srv.Canonical = canon.ToList(); - } - - return srvRecords; - } - } -} diff --git a/Bruce/Program.cs b/Bruce/Program.cs index 538fd174..31ce2829 100644 --- a/Bruce/Program.cs +++ b/Bruce/Program.cs @@ -1,9 +1,8 @@ -using System; +using Kerberos.NET.PortableDns; +using System; using System.Diagnostics; using System.IO; using System.Linq; -using Kerberos.NET.CommandLine.Dns; -using Kerberos.NET.Dns; namespace Kerberos.NET.CommandLine { @@ -12,7 +11,10 @@ class Program [STAThread] static void Main(string[] args) { - DnsQuery.RegisterImplementation(new PlatformIndependentDnsClient()); + if (!OSPlatform.IsWindows) + { + PortableDnsClient.Configure(); + } var assembly = Path.GetFileNameWithoutExtension(Process.GetCurrentProcess().ProcessName); From df5f8ac9a646350edf6d0b8293f8ed49149e48ee Mon Sep 17 00:00:00 2001 From: petrsnd Date: Thu, 1 May 2025 21:57:08 -0600 Subject: [PATCH 03/13] Building on Windows with up-to-date targets The goal is to get Bruce working on Linux with platform-agnostic DNS resolution out-of-the-box, but Bruce refs the Windows forms project for KerbDumpCommand, although code is short-circuited for non-Windows --- Bruce/Bruce.csproj | 12 ++++++++++-- Samples/KerbDumpCore/KerbDumpCore.csproj | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Bruce/Bruce.csproj b/Bruce/Bruce.csproj index db707155..57b9b78c 100644 --- a/Bruce/Bruce.csproj +++ b/Bruce/Bruce.csproj @@ -1,8 +1,15 @@  + + net8.0-windows + + + + net8.0 + + Exe - netcoreapp3.1 Kerberos.NET.CommandLine Major @@ -39,7 +46,8 @@ - + diff --git a/Samples/KerbDumpCore/KerbDumpCore.csproj b/Samples/KerbDumpCore/KerbDumpCore.csproj index 46869fbe..d778b50e 100644 --- a/Samples/KerbDumpCore/KerbDumpCore.csproj +++ b/Samples/KerbDumpCore/KerbDumpCore.csproj @@ -2,7 +2,7 @@ Library - netcoreapp3.1 + net8.0-windows true false From 496e8caa394c1a12e8778d2dd659859759291738 Mon Sep 17 00:00:00 2001 From: petrsnd Date: Fri, 2 May 2025 09:36:15 -0600 Subject: [PATCH 04/13] Nullable handling and generate assembly info Code written prior to C# 8 generally has warnings related to nullable reference type warnings. Setting nullable as diabled for the projects and just enabling it for the one place it is used in a more recent update makes the warnings go away. Generating assembly info allows the target for net8.0-windows to set runtime versioning to Windows which avoids a bunch of CA1416 errors. --- Kerberos.NET/Cache/FileHandle.cs | 1 + Kerberos.NET/Kerberos.NET.csproj | 1 + Samples/KerbDumpCore/KerbDumpCore.csproj | 5 +++-- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Kerberos.NET/Cache/FileHandle.cs b/Kerberos.NET/Cache/FileHandle.cs index 061451ed..bbaf4323 100644 --- a/Kerberos.NET/Cache/FileHandle.cs +++ b/Kerberos.NET/Cache/FileHandle.cs @@ -2,6 +2,7 @@ // Licensed to The .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // ----------------------------------------------------------------------- +#nullable enable using System; using System.IO; diff --git a/Kerberos.NET/Kerberos.NET.csproj b/Kerberos.NET/Kerberos.NET.csproj index 654aed17..fb13aaf2 100644 --- a/Kerberos.NET/Kerberos.NET.csproj +++ b/Kerberos.NET/Kerberos.NET.csproj @@ -5,6 +5,7 @@ A cross-platform, managed-code Kerberos Ticket parsing, validation, and authentication library. security kerberos true + disable diff --git a/Samples/KerbDumpCore/KerbDumpCore.csproj b/Samples/KerbDumpCore/KerbDumpCore.csproj index d778b50e..30357231 100644 --- a/Samples/KerbDumpCore/KerbDumpCore.csproj +++ b/Samples/KerbDumpCore/KerbDumpCore.csproj @@ -1,11 +1,12 @@ - + Library net8.0-windows + disable true - false + true KerbDumpCore KerbDump From f80cc9f9d2dd7000690384804e628e3d5ba9c935 Mon Sep 17 00:00:00 2001 From: petrsnd Date: Fri, 2 May 2025 13:53:25 -0600 Subject: [PATCH 05/13] Conditionally remove Windows Forms code Windows Forms code does not build on Linux so I changed this to use precompiler directives. Moved to more up-to-date version of C# to avoid additional issues with nullable. --- Bruce/CommandLine/KerberosDumpCommand.cs | 14 +++++++++----- Bruce/CommandLine/KerberosPasswordCommand.cs | 5 ----- Kerberos.NET/Kerberos.NET.csproj | 1 + 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Bruce/CommandLine/KerberosDumpCommand.cs b/Bruce/CommandLine/KerberosDumpCommand.cs index 142f17b5..68183124 100644 --- a/Bruce/CommandLine/KerberosDumpCommand.cs +++ b/Bruce/CommandLine/KerberosDumpCommand.cs @@ -4,8 +4,10 @@ // ----------------------------------------------------------------------- using System.Threading.Tasks; +#if WINDOWS using System.Windows.Forms; using KerbDump; +#endif namespace Kerberos.NET.CommandLine { @@ -14,8 +16,10 @@ public class KerberosDumpCommand : BaseCommand { static KerberosDumpCommand() { +#if WINDOWS Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); +#endif } public KerberosDumpCommand(CommandLineParameters parameters) @@ -29,11 +33,7 @@ public KerberosDumpCommand(CommandLineParameters parameters) public override Task Execute() { - if (!OSPlatform.IsWindows) - { - return Task.FromResult(false); - } - +#if WINDOWS using (var form = new DecoderForm() { Ticket = this.Ticket, @@ -44,6 +44,10 @@ public override Task Execute() } return Task.FromResult(true); +#else + return Task.FromResult(false); +#endif } } } + diff --git a/Bruce/CommandLine/KerberosPasswordCommand.cs b/Bruce/CommandLine/KerberosPasswordCommand.cs index c007b6da..83ccf59c 100644 --- a/Bruce/CommandLine/KerberosPasswordCommand.cs +++ b/Bruce/CommandLine/KerberosPasswordCommand.cs @@ -3,17 +3,12 @@ // The .NET Foundation licenses this file to you under the MIT license. // ----------------------------------------------------------------------- -using Kerberos.NET.Configuration; using Kerberos.NET.Credentials; -using Kerberos.NET.Crypto; using Kerberos.NET.Entities; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using System; -using System.Linq; -using System.Security.Cryptography.X509Certificates; using System.Threading.Tasks; -using System.Windows.Forms; namespace Kerberos.NET.CommandLine { diff --git a/Kerberos.NET/Kerberos.NET.csproj b/Kerberos.NET/Kerberos.NET.csproj index fb13aaf2..af3312f2 100644 --- a/Kerberos.NET/Kerberos.NET.csproj +++ b/Kerberos.NET/Kerberos.NET.csproj @@ -1,6 +1,7 @@  netstandard2.0 + 9.0 Kerberos.NET library A cross-platform, managed-code Kerberos Ticket parsing, validation, and authentication library. security kerberos From 4724ccea52dae60a3f98c42cd4bc992273cbcf56 Mon Sep 17 00:00:00 2001 From: petrsnd Date: Fri, 2 May 2025 13:56:51 -0600 Subject: [PATCH 06/13] Don't detect line endings as diffs on Linux XslTransform is running on Linux, but it is reporting everything as changed. Added support to use diff on Unix to properly detect whether something has actually changed. --- Kerberos.NET/Asn1/AsnXml.targets | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Kerberos.NET/Asn1/AsnXml.targets b/Kerberos.NET/Asn1/AsnXml.targets index 2cce5696..ef5f99b2 100644 --- a/Kerberos.NET/Asn1/AsnXml.targets +++ b/Kerberos.NET/Asn1/AsnXml.targets @@ -13,7 +13,6 @@ - @@ -32,6 +31,13 @@ + + + + - \ No newline at end of file + From 023409258bbe7bc77c1d52b58cba1100703626d5 Mon Sep 17 00:00:00 2001 From: petrsnd Date: Fri, 2 May 2025 14:31:03 -0600 Subject: [PATCH 07/13] Fix help command alias printing --- Bruce/CommandLine/KerberosHelpCommand.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Bruce/CommandLine/KerberosHelpCommand.cs b/Bruce/CommandLine/KerberosHelpCommand.cs index 90248e6e..d134f178 100644 --- a/Bruce/CommandLine/KerberosHelpCommand.cs +++ b/Bruce/CommandLine/KerberosHelpCommand.cs @@ -123,11 +123,11 @@ private void WriteCommandLabel(Type type, int max = 0) if (string.Equals(descName, desc, StringComparison.OrdinalIgnoreCase)) { - this.WriteLine(string.Format(format, label), attr.Description, commands.Skip(1)); + this.WriteLine(string.Format(format, label), attr.Description, string.Join(", ", commands.Skip(1))); } else { - this.WriteLine(string.Format(format, label), desc, commands.Skip(1)); + this.WriteLine(string.Format(format, label), desc, string.Join(", ", commands.Skip(1))); } } } From e094d330b0d4d8780ff6257a1bfb5cb30a3261dd Mon Sep 17 00:00:00 2001 From: petrsnd Date: Fri, 2 May 2025 17:33:33 -0600 Subject: [PATCH 08/13] Use XDG_CONFIG_HOME by default Rather than defaulting to the system-wide krb5.conf on Linux, it seemed more appropriate to use this value for a CurrentUser krb5.conf. For more information see https://specifications.freedesktop.org/basedir-spec/latest/ --- Kerberos.NET/Configuration/Krb5Config.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Kerberos.NET/Configuration/Krb5Config.cs b/Kerberos.NET/Configuration/Krb5Config.cs index c4b6842c..f45e16d3 100644 --- a/Kerberos.NET/Configuration/Krb5Config.cs +++ b/Kerberos.NET/Configuration/Krb5Config.cs @@ -77,7 +77,7 @@ public Krb5Config() envVar: "%KRB5_CONFIG%", winPath: "%APPDATA%\\Kerberos.NET\\", osxPath: "Library/Preferences/Kerberos.NET/", - linuxPath: "/etc/" + linuxPath: "%HOME%/.config/Kerberos.NET/" // use XDG_CONFIG_HOME default ); public static string ServiceConfigurationPath => GetFilePath( @@ -117,9 +117,10 @@ public static Krb5Config CurrentUser(string path = null) path = DefaultUserConfigurationPath; } - if (File.Exists(path)) + var expandedPath = Environment.ExpandEnvironmentVariables(path); + if (File.Exists(expandedPath)) { - return Krb5ConfigurationSerializer.Deserialize(File.ReadAllText(path)).ToConfigObject(); + return Krb5ConfigurationSerializer.Deserialize(File.ReadAllText(expandedPath)).ToConfigObject(); } return Default(); From bbf1d798268b66b71efb7271681e00e59b4cc0ba Mon Sep 17 00:00:00 2001 From: petrsnd Date: Tue, 20 May 2025 17:00:40 -0600 Subject: [PATCH 09/13] Attrs must be constants, use conditional compilation Krb5Config dynamically builds paths using the GetFilePath() method to deal with differing operating system defaults. Krb5ConfigDefaults cannot use that because it relies on DefaultValueAttribute. The default ccache name crashes immediately with an illegal Mutex name. Conditional compilation is the only solution without rewriting a lot of krb5.conf handling code. --- .../Configuration/Krb5ConfigDefaults.cs | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/Kerberos.NET/Configuration/Krb5ConfigDefaults.cs b/Kerberos.NET/Configuration/Krb5ConfigDefaults.cs index ec948aa5..74023bf8 100644 --- a/Kerberos.NET/Configuration/Krb5ConfigDefaults.cs +++ b/Kerberos.NET/Configuration/Krb5ConfigDefaults.cs @@ -49,21 +49,39 @@ public class Krb5ConfigDefaults : Krb5ConfigObject /// /// This relation specifies the name of the default credential cache. The default is "FILE:%APPDATA%\Kerberos.NET\.krb5cc". /// +#if WINDOWS [DefaultValue("FILE:%APPDATA%\\Kerberos.NET\\.krb5cc")] +#elif LINUX + [DefaultValue("FILE:%HOME%/.config/Kerberos.NET/.krb5cc")] +#else + [DefaultValue("FILE:%HOME%/Library/Preferences/Kerberos.NET/.krb5cc")] +#endif [DisplayName("default_ccache_name")] public string DefaultCCacheName { get; set; } /// /// This relation specifies the name of the default keytab for obtaining client credentials. The default is "%APPDATA%\\Kerberos.NET\\client.keytab". /// - [DefaultValue("%APPDATA%\\Kerberos.NET\\.keytab")] +#if WINDOWS + [DefaultValue("%APPDATA%\\Kerberos.NET\\client.keytab")] +#elif LINUX + [DefaultValue("%HOME%/.config/Kerberos.NET/client.keytab")] +#else + [DefaultValue("%HOME%/Library/Preferences/Kerberos.NET/client.keytab")] +#endif [DisplayName("default_client_keytab_name")] public string DefaultClientKeytabName { get; set; } /// /// This relation specifies the default keytab name to be used by application servers such as sshd. The default is "%APPDATA%\\Kerberos.NET\\server.keytab". /// - [DefaultValue("%APPDATA%\\Kerberos.NET\\.keytab")] +#if WINDOWS + [DefaultValue("%APPDATA%\\Kerberos.NET\\server.keytab")] +#elif LINUX + [DefaultValue("%HOME%/.config/Kerberos.NET/server.keytab")] +#else + [DefaultValue("%HOME%/Library/Preferences/Kerberos.NET/server.keytab")] +#endif [DisplayName("default_keytab_name")] public string DefaultKeytabName { get; set; } From 0a29b6cca8ef286c3747182bae73d208e5f05f51 Mon Sep 17 00:00:00 2001 From: petrsnd Date: Tue, 20 May 2025 21:47:29 -0600 Subject: [PATCH 10/13] Added config comments and variable expansion If we want Kerberos.NET to be completely compliant with MIT Kerberos defaults, then we can change some of the paths. The location of krb5.conf is usually system-wide (/etc/krb5.conf) and the kdc.conf is in the $LOCALSTATEDIR/krb5kdc. /etc isn't a user configuration location so I changed it to $XDG_CONFIG_HOME, and I added the ability to expand variables set in the krb5.conf. That can allow putting the krb5ccache in the home directory with %HOME%. We should consider honoring the %KRB5CCNAME% environment variable. --- .gitignore | 4 +++- Kerberos.NET/Configuration/Krb5Config.cs | 13 ++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index fbd71724..036c443f 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,8 @@ bld/ # Visual Studio 2015 cache/options directory .vs/ +# Visual Studio Code directory +.vscode/ # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/ @@ -285,4 +287,4 @@ __pycache__/ *.btp.cs *.btm.cs *.odx.cs -*.xsd.cs \ No newline at end of file +*.xsd.cs diff --git a/Kerberos.NET/Configuration/Krb5Config.cs b/Kerberos.NET/Configuration/Krb5Config.cs index f45e16d3..f6a12fad 100644 --- a/Kerberos.NET/Configuration/Krb5Config.cs +++ b/Kerberos.NET/Configuration/Krb5Config.cs @@ -74,14 +74,18 @@ public Krb5Config() public Krb5Logging Logging { get; private set; } public static string UserConfigurationPath => GetFilePath( - envVar: "%KRB5_CONFIG%", + envVar: "%KRB5_CONFIG%", // %KRB_CONFIG% is being used to specify the user + // configuration path, but it should be the path to krb5.conf itself + // (see https://web.mit.edu/kerberos/krb5-1.12/doc/admin/env_variables.html) winPath: "%APPDATA%\\Kerberos.NET\\", osxPath: "Library/Preferences/Kerberos.NET/", linuxPath: "%HOME%/.config/Kerberos.NET/" // use XDG_CONFIG_HOME default ); public static string ServiceConfigurationPath => GetFilePath( - envVar: "%KRB5_KDC_PROFILE%", + envVar: "%KRB5_KDC_PROFILE%", // %KRB5_KDC_PROFILE% is being used to specify the service + // configuration path, but it should be the path to kdc.conf itself + // (see https://web.mit.edu/kerberos/krb5-1.12/doc/admin/env_variables.html) winPath: "%APPDATA%\\Kerberos.NET\\", osxPath: "Library/Preferences/Kerberos.NET/", linuxPath: "/var/krb5kdc" @@ -117,6 +121,7 @@ public static Krb5Config CurrentUser(string path = null) path = DefaultUserConfigurationPath; } + // Expansion allows the use of environment variables in krb5.conf, but they must be in %VAR% format var expandedPath = Environment.ExpandEnvironmentVariables(path); if (File.Exists(expandedPath)) { @@ -181,7 +186,9 @@ private static string GetFilePath(string envVar, string winPath, string osxPath, } else if (OSPlatform.IsLinux) { - return linuxPath; + // Environment variables use %VAR% format + // (see https://github.com/dotnet/runtime/issues/25792) + return Environment.ExpandEnvironmentVariables(linuxPath); } return string.Empty; From 7811d43b52641152e880bad769c0eabea12faa5f Mon Sep 17 00:00:00 2001 From: petrsnd Date: Tue, 1 Jul 2025 19:20:24 -0600 Subject: [PATCH 11/13] Use nullable regions for code that has introduced nullable --- Kerberos.NET/Cache/FileHandle.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Kerberos.NET/Cache/FileHandle.cs b/Kerberos.NET/Cache/FileHandle.cs index bbaf4323..53da0d04 100644 --- a/Kerberos.NET/Cache/FileHandle.cs +++ b/Kerberos.NET/Cache/FileHandle.cs @@ -2,7 +2,6 @@ // Licensed to The .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // ----------------------------------------------------------------------- -#nullable enable using System; using System.IO; @@ -21,8 +20,9 @@ internal class FileHandle : IDisposable private readonly FileMode mode; private readonly FileAccess access; private readonly FileShare share; +#nullable enable private static readonly MethodInfo? SetUnixFileMode = TryGetSetUnixFileMode(); - +#nullable disable private static readonly TimeSpan LockWaitTimeout = TimeSpan.FromMilliseconds(5000); public FileHandle(string file, FileMode mode, FileAccess access, FileShare share) @@ -79,6 +79,7 @@ private static string GetObjectName(string file, string type) .Replace(Path.VolumeSeparatorChar, '_'); } +#nullable enable private static MethodInfo? TryGetSetUnixFileMode() { MethodInfo? mi = null; @@ -91,11 +92,15 @@ private static string GetObjectName(string file, string type) { mi = typeof(File).GetMethod("SetUnixFileMode", new Type[] { typeof(SafeFileHandle), Type.GetType("System.IO.UnixFileMode") }); } - catch { } + catch + { + // ignored + } } return mi; } +#nullable disable private class FileLock : IDisposable { From abb2a626898c563cda11365c03560e6151f06b6e Mon Sep 17 00:00:00 2001 From: petrsnd Date: Tue, 9 Sep 2025 16:06:19 -0600 Subject: [PATCH 12/13] Make sure that Krb5ConfigDefaults uses correct values on each supported platform use .NET 8 updated OS detection but change as little code as possible --- Kerberos.NET/Configuration/Krb5ConfigDefaults.cs | 12 +++++++++--- Kerberos.NET/Kerberos.NET.csproj | 12 ++++++++++++ Kerberos.NET/OSPlatform.cs | 10 ++++------ 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/Kerberos.NET/Configuration/Krb5ConfigDefaults.cs b/Kerberos.NET/Configuration/Krb5ConfigDefaults.cs index 74023bf8..886d4da1 100644 --- a/Kerberos.NET/Configuration/Krb5ConfigDefaults.cs +++ b/Kerberos.NET/Configuration/Krb5ConfigDefaults.cs @@ -53,8 +53,10 @@ public class Krb5ConfigDefaults : Krb5ConfigObject [DefaultValue("FILE:%APPDATA%\\Kerberos.NET\\.krb5cc")] #elif LINUX [DefaultValue("FILE:%HOME%/.config/Kerberos.NET/.krb5cc")] -#else +#elif MACOS [DefaultValue("FILE:%HOME%/Library/Preferences/Kerberos.NET/.krb5cc")] +#else + #error Unknown platform #endif [DisplayName("default_ccache_name")] public string DefaultCCacheName { get; set; } @@ -66,8 +68,10 @@ public class Krb5ConfigDefaults : Krb5ConfigObject [DefaultValue("%APPDATA%\\Kerberos.NET\\client.keytab")] #elif LINUX [DefaultValue("%HOME%/.config/Kerberos.NET/client.keytab")] -#else +#elif MACOS [DefaultValue("%HOME%/Library/Preferences/Kerberos.NET/client.keytab")] +#else + #error Unknown platform #endif [DisplayName("default_client_keytab_name")] public string DefaultClientKeytabName { get; set; } @@ -79,8 +83,10 @@ public class Krb5ConfigDefaults : Krb5ConfigObject [DefaultValue("%APPDATA%\\Kerberos.NET\\server.keytab")] #elif LINUX [DefaultValue("%HOME%/.config/Kerberos.NET/server.keytab")] -#else +#elif MACOS [DefaultValue("%HOME%/Library/Preferences/Kerberos.NET/server.keytab")] +#else + #error Unknown platform #endif [DisplayName("default_keytab_name")] public string DefaultKeytabName { get; set; } diff --git a/Kerberos.NET/Kerberos.NET.csproj b/Kerberos.NET/Kerberos.NET.csproj index af3312f2..781b0f23 100644 --- a/Kerberos.NET/Kerberos.NET.csproj +++ b/Kerberos.NET/Kerberos.NET.csproj @@ -13,6 +13,18 @@ WEAKCRYPTO + + $(DefineConstants);WINDOWS + + + + $(DefineConstants);LINUX + + + + $(DefineConstants);MACOS + + diff --git a/Kerberos.NET/OSPlatform.cs b/Kerberos.NET/OSPlatform.cs index e77447ae..52434b92 100644 --- a/Kerberos.NET/OSPlatform.cs +++ b/Kerberos.NET/OSPlatform.cs @@ -1,16 +1,14 @@ using System; +using RtIs = System.Runtime.InteropServices; namespace Kerberos.NET { public static class OSPlatform { - public static readonly bool IsWindows = Environment.OSVersion.Platform == PlatformID.Win32S - || Environment.OSVersion.Platform == PlatformID.Win32Windows - || Environment.OSVersion.Platform == PlatformID.Win32NT - || Environment.OSVersion.Platform == PlatformID.WinCE; + public static readonly bool IsWindows = RtIs.RuntimeInformation.IsOSPlatform(RtIs.OSPlatform.Windows); - public static readonly bool IsLinux = Environment.OSVersion.Platform == PlatformID.Unix; + public static readonly bool IsLinux = RtIs.RuntimeInformation.IsOSPlatform(RtIs.OSPlatform.Linux); - public static readonly bool IsOsX = Environment.OSVersion.Platform == PlatformID.MacOSX; + public static readonly bool IsOsX = RtIs.RuntimeInformation.IsOSPlatform(RtIs.OSPlatform.OSX); } } From 0a45b9bf75b1e013e68c419fe42312a3f6186cc4 Mon Sep 17 00:00:00 2001 From: Steve Syfuhs Date: Wed, 10 Sep 2025 20:55:53 -0700 Subject: [PATCH 13/13] Drop moniker and platform id for packaging --- Bruce/Bruce.csproj | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Bruce/Bruce.csproj b/Bruce/Bruce.csproj index 57b9b78c..ea86f0de 100644 --- a/Bruce/Bruce.csproj +++ b/Bruce/Bruce.csproj @@ -50,4 +50,11 @@ Condition="'$(OS)' == 'Windows_NT'" /> + + + + + + +