Attempt to support unconfigured kerberos and weird Mac cred cache

This commit is contained in:
2026-03-31 12:43:36 +02:00
parent 11969e8f46
commit 5d2a80bd30

View File

@@ -10,6 +10,7 @@ import (
"os"
"os/signal"
"path/filepath"
"runtime"
"strings"
"syscall"
"time"
@@ -61,16 +62,31 @@ func credFetch(server, username string, noKerberos bool, logf func(string, ...an
func credFetchKerberos(url string, logf func(string, ...any)) ([]byte, error) {
krb5cfgPath := krb5ConfigPath()
logf("Kerberos: loading config from %s", krb5cfgPath)
krb5cfg, err := config.Load(krb5cfgPath)
if err != nil {
return nil, fmt.Errorf("loading krb5 config: %w", err)
var krb5cfg *config.Config
if _, statErr := os.Stat(krb5cfgPath); os.IsNotExist(statErr) && os.Getenv("KRB5_CONFIG") == "" {
logf("Kerberos: %s not found, using default config (KDC discovery via DNS)", krb5cfgPath)
krb5cfg = config.New()
krb5cfg.LibDefaults.DNSLookupKDC = true
} else {
var err error
krb5cfg, err = config.Load(krb5cfgPath)
if err != nil {
return nil, fmt.Errorf("loading krb5 config: %w", err)
}
}
ccPath := ccachePath()
ccPath, err := ccachePath()
if err != nil {
return nil, err
}
logf("Kerberos: loading credential cache from %s", ccPath)
ccache, err := credentials.LoadCCache(ccPath)
if err != nil {
return nil, fmt.Errorf("no credential cache (%w) — run 'kinit'", err)
hint := "run 'kinit'"
if runtime.GOOS == "darwin" && os.Getenv("KRB5CCNAME") == "" {
hint = fmt.Sprintf("on macOS, run: kinit -c /tmp/krb5cc_%d", os.Getuid())
}
return nil, fmt.Errorf("no credential cache (%w) — %s", err, hint)
}
cl, err := krb5client.NewFromCCache(ccache, krb5cfg, krb5client.DisablePAFXFAST(true))
@@ -224,15 +240,25 @@ func krb5ConfigPath() string {
return cmp.Or(os.Getenv("KRB5_CONFIG"), "/etc/krb5.conf")
}
// ccachePath returns the path to the active Kerberos credential cache.
// Respects $KRB5CCNAME; strips the "FILE:" prefix if present.
// Non-file ccache types (API:, KEYRING:, DIR:) are not supported by gokrb5
// and will produce an error when LoadCCache is called.
func ccachePath() string {
// ccachePath returns the path to the active Kerberos credential cache, or an
// error if $KRB5CCNAME names a non-file cache type that gokrb5 cannot read.
//
// On macOS, kinit defaults to API: caches. Work around it with:
//
// kinit -c /tmp/krb5cc_$(id -u)
func ccachePath() (string, error) {
if v := os.Getenv("KRB5CCNAME"); v != "" {
return strings.TrimPrefix(v, "FILE:")
for _, prefix := range []string{"API:", "KEYRING:", "DIR:", "KCM:"} {
if strings.HasPrefix(v, prefix) {
return "", fmt.Errorf(
"credential cache type %s is not supported (gokrb5 requires a file-based cache)\n"+
"hint: re-run kinit with: kinit -c /tmp/krb5cc_%d",
prefix, os.Getuid())
}
}
return strings.TrimPrefix(v, "FILE:"), nil
}
return fmt.Sprintf("/tmp/krb5cc_%d", os.Getuid())
return fmt.Sprintf("/tmp/krb5cc_%d", os.Getuid()), nil
}
// ── Password prompt ────────────────────────────────────────────────────────────