92 lines
2.7 KiB
C#
92 lines
2.7 KiB
C#
using System;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using Npgsql.Logging;
|
|
|
|
namespace Npgsql;
|
|
|
|
/// <summary>
|
|
/// Launches MIT Kerberos klist and parses out the default principal from it.
|
|
/// Caches the result.
|
|
/// </summary>
|
|
class KerberosUsernameProvider
|
|
{
|
|
static bool _performedDetection;
|
|
static string? _principalWithRealm;
|
|
static string? _principalWithoutRealm;
|
|
|
|
static readonly NpgsqlLogger Log = NpgsqlLogManager.CreateLogger(nameof(KerberosUsernameProvider));
|
|
|
|
internal static string? GetUsername(bool includeRealm)
|
|
{
|
|
if (!_performedDetection)
|
|
{
|
|
DetectUsername();
|
|
_performedDetection = true;
|
|
}
|
|
return includeRealm ? _principalWithRealm : _principalWithoutRealm;
|
|
}
|
|
|
|
static void DetectUsername()
|
|
{
|
|
var klistPath = FindInPath("klist");
|
|
if (klistPath == null)
|
|
{
|
|
Log.Debug("klist not found in PATH, skipping Kerberos username detection");
|
|
return;
|
|
}
|
|
|
|
var processStartInfo = new ProcessStartInfo
|
|
{
|
|
FileName = klistPath,
|
|
RedirectStandardOutput = true,
|
|
RedirectStandardError = true,
|
|
UseShellExecute = false
|
|
};
|
|
var process = Process.Start(processStartInfo);
|
|
if (process is null)
|
|
{
|
|
Log.Debug($"klist process could not be started");
|
|
return;
|
|
}
|
|
|
|
process.WaitForExit();
|
|
if (process.ExitCode != 0)
|
|
{
|
|
Log.Debug($"klist exited with code {process.ExitCode}: {process.StandardError.ReadToEnd()}");
|
|
return;
|
|
}
|
|
|
|
var line = default(string);
|
|
for (var i = 0; i < 2; i++)
|
|
if ((line = process.StandardOutput.ReadLine()) == null)
|
|
{
|
|
Log.Debug("Unexpected output from klist, aborting Kerberos username detection");
|
|
return;
|
|
}
|
|
|
|
var components = line!.Split(':');
|
|
if (components.Length != 2)
|
|
{
|
|
Log.Debug("Unexpected output from klist, aborting Kerberos username detection");
|
|
return;
|
|
}
|
|
|
|
var principalWithRealm = components[1].Trim();
|
|
components = principalWithRealm.Split('@');
|
|
if (components.Length != 2)
|
|
{
|
|
Log.Debug($"Badly-formed default principal {principalWithRealm} from klist, aborting Kerberos username detection");
|
|
return;
|
|
}
|
|
|
|
_principalWithRealm = principalWithRealm;
|
|
_principalWithoutRealm = components[0];
|
|
}
|
|
|
|
static string? FindInPath(string name) => Environment.GetEnvironmentVariable("PATH")
|
|
?.Split(Path.PathSeparator)
|
|
.Select(p => Path.Combine(p, name))
|
|
.FirstOrDefault(File.Exists);
|
|
} |