From 28f6319b77d35c6da6b99ad7e35d0d5602dc2ee6 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Fri, 10 Apr 2026 18:03:29 +0300 Subject: Fix known-hosts trust deadlock, host key stat, and optional nozstd build - stdout logger: release mutex while waiting on pause resume so prompt callbacks can log (fixes hang after trusting new hosts; known_hosts was written but Resume never ran). - known hosts callback: stop borrowing the SSH dial throttle channel (could block or interact badly with parallel handshakes). - host key path: use errors.Is(..., fs.ErrNotExist) for RootedPath.Stat wrapped errors; stat errors now fail fast instead of mis-read. - public key path: same ErrNotExist check for authorized_keys miss. - Build: optional DTAIL_NO_ZSTD=yes / nozstd tag for CGO-free builds; split zstd readers into tagged files. - Docs/examples: firewalld note for port 2222, log prune timer+script, SSHBindAddress note, dserver unit disabled-by-default comment; firewalld helper script example. - Regression test for stdout pause/mutex behavior. Made-with: Cursor --- internal/ssh/server/hostkey.go | 28 ++++++++++++++++------------ internal/ssh/server/publickeycallback.go | 4 +++- 2 files changed, 19 insertions(+), 13 deletions(-) (limited to 'internal/ssh/server') diff --git a/internal/ssh/server/hostkey.go b/internal/ssh/server/hostkey.go index 1df2287..1315351 100644 --- a/internal/ssh/server/hostkey.go +++ b/internal/ssh/server/hostkey.go @@ -1,7 +1,8 @@ package server import ( - "os" + "errors" + iofs "io/fs" "github.com/mimecast/dtail/internal/config" "github.com/mimecast/dtail/internal/io/dlog" @@ -31,18 +32,21 @@ func PrivateHostKey(hostKeyFile string, hostKeyBits int) []byte { } _, err = hostKeyPath.Stat() - - if os.IsNotExist(err) { - dlog.Server.Info("Generating private server RSA host key") - pem, err := generatePrivateHostKey(hostKeyBits) - if err != nil { - dlog.Server.FatalPanic("Failed to generate private server RSA host key", err) - } - if err := storePrivateHostKey(hostKeyPath, pem); err != nil { - dlog.Server.Error("Unable to write private server RSA host key to file", - hostKeyFile, err) + if err != nil { + // os.IsNotExist does not unwrap fmt.Errorf chains from RootedPath.Stat; use errors.Is. + if errors.Is(err, iofs.ErrNotExist) { + dlog.Server.Info("Generating private server RSA host key") + pem, genErr := generatePrivateHostKey(hostKeyBits) + if genErr != nil { + dlog.Server.FatalPanic("Failed to generate private server RSA host key", genErr) + } + if storeErr := storePrivateHostKey(hostKeyPath, pem); storeErr != nil { + dlog.Server.Error("Unable to write private server RSA host key to file", + hostKeyFile, storeErr) + } + return pem } - return pem + dlog.Server.FatalPanic("Cannot stat private server RSA host key path", hostKeyFile, err) } dlog.Server.Info("Reading private server RSA host key from file", hostKeyFile) diff --git a/internal/ssh/server/publickeycallback.go b/internal/ssh/server/publickeycallback.go index 3afbfba..df83bf6 100644 --- a/internal/ssh/server/publickeycallback.go +++ b/internal/ssh/server/publickeycallback.go @@ -1,7 +1,9 @@ package server import ( + "errors" "fmt" + iofs "io/fs" "os" goUser "os/user" "path/filepath" @@ -142,7 +144,7 @@ func findAuthorizedKeysPath(user *user.User, cacheDir, cwd string, if _, err = rootedAuthorizedKeysPath.Stat(); err == nil { return rootedAuthorizedKeysPath, nil } - if !os.IsNotExist(err) { + if !errors.Is(err, iofs.ErrNotExist) { return fs.RootedPath{}, err } -- cgit v1.2.3