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/.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/Bruce/Bruce.csproj b/Bruce/Bruce.csproj
index 8a795643..ea86f0de 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
@@ -33,13 +40,21 @@
-
+
-
+
+
+
+
+
+
+
+
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/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)));
}
}
}
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/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);
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/Bruce/Dns/PlatformIndependentDnsClient.cs b/Kerberos.NET.PortableDns/PortableDnsImplementation.cs
similarity index 67%
rename from Bruce/Dns/PlatformIndependentDnsClient.cs
rename to Kerberos.NET.PortableDns/PortableDnsImplementation.cs
index 765b3448..f2c5f9cb 100644
--- a/Bruce/Dns/PlatformIndependentDnsClient.cs
+++ b/Kerberos.NET.PortableDns/PortableDnsImplementation.cs
@@ -1,27 +1,30 @@
-using System;
+using DnsClient;
+using Kerberos.NET.Dns;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
-using DnsClient;
-using Kerberos.NET.Dns;
-namespace Kerberos.NET.CommandLine.Dns
+namespace Kerberos.NET.PortableDns
{
- internal class PlatformIndependentDnsClient : IKerberosDnsQuery
+ internal class PortableDnsImplementation : IKerberosDnsQuery
{
- private static readonly WindowsDnsQuery WindowsDns = new WindowsDnsQuery();
-
- public async Task> Query(string query, DnsRecordType type)
+ static PortableDnsImplementation()
{
- if (WindowsDns.IsSupported)
- {
- return await WindowsDns.Query(query, type);
- }
+ DnsQuery.RegisterImplementation(new PortableDnsImplementation());
+ }
- var client = new LookupClient();
+ public static LookupClientOptions Options { get; set; } = new LookupClientOptions();
- var response = await client.QueryAsync(query, (QueryType)type);
+ 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,
@@ -38,9 +41,7 @@ public async Task> Query(string query, DnsRecordT
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();
}
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}
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
+
diff --git a/Kerberos.NET/Cache/FileHandle.cs b/Kerberos.NET/Cache/FileHandle.cs
index 061451ed..53da0d04 100644
--- a/Kerberos.NET/Cache/FileHandle.cs
+++ b/Kerberos.NET/Cache/FileHandle.cs
@@ -20,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)
@@ -78,6 +79,7 @@ private static string GetObjectName(string file, string type)
.Replace(Path.VolumeSeparatorChar, '_');
}
+#nullable enable
private static MethodInfo? TryGetSetUnixFileMode()
{
MethodInfo? mi = null;
@@ -90,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
{
diff --git a/Kerberos.NET/Configuration/Krb5Config.cs b/Kerberos.NET/Configuration/Krb5Config.cs
index c4b6842c..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: "/etc/"
+ 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,9 +121,11 @@ public static Krb5Config CurrentUser(string path = null)
path = DefaultUserConfigurationPath;
}
- if (File.Exists(path))
+ // 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))
{
- return Krb5ConfigurationSerializer.Deserialize(File.ReadAllText(path)).ToConfigObject();
+ return Krb5ConfigurationSerializer.Deserialize(File.ReadAllText(expandedPath)).ToConfigObject();
}
return Default();
@@ -180,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;
diff --git a/Kerberos.NET/Configuration/Krb5ConfigDefaults.cs b/Kerberos.NET/Configuration/Krb5ConfigDefaults.cs
index ec948aa5..886d4da1 100644
--- a/Kerberos.NET/Configuration/Krb5ConfigDefaults.cs
+++ b/Kerberos.NET/Configuration/Krb5ConfigDefaults.cs
@@ -49,21 +49,45 @@ 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")]
+#elif MACOS
+ [DefaultValue("FILE:%HOME%/Library/Preferences/Kerberos.NET/.krb5cc")]
+#else
+ #error Unknown platform
+#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")]
+#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; }
///
/// 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")]
+#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 654aed17..781b0f23 100644
--- a/Kerberos.NET/Kerberos.NET.csproj
+++ b/Kerberos.NET/Kerberos.NET.csproj
@@ -1,16 +1,30 @@
netstandard2.0
+ 9.0
Kerberos.NET library
A cross-platform, managed-code Kerberos Ticket parsing, validation, and authentication library.
security kerberos
true
+ disable
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);
}
}
diff --git a/Samples/KerbDumpCore/KerbDumpCore.csproj b/Samples/KerbDumpCore/KerbDumpCore.csproj
index 46869fbe..30357231 100644
--- a/Samples/KerbDumpCore/KerbDumpCore.csproj
+++ b/Samples/KerbDumpCore/KerbDumpCore.csproj
@@ -1,11 +1,12 @@
-
+
Library
- netcoreapp3.1
+ net8.0-windows
+ disable
true
- false
+ true
KerbDumpCore
KerbDump