hecate: preserve known_hosts ownership during key repair

This commit is contained in:
Brad Stein 2026-04-04 22:44:19 -03:00
parent b5f27a79e0
commit 4c03be1e9b

View File

@ -8,6 +8,7 @@ import (
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"strings" "strings"
"syscall"
"time" "time"
) )
@ -134,11 +135,14 @@ func RepairKnownHosts(ctx context.Context, logger *log.Logger, knownHostsFiles [
} }
func removeKnownHostEntry(ctx context.Context, logger *log.Logger, file string, entry string) { func removeKnownHostEntry(ctx context.Context, logger *log.Logger, file string, entry string) {
uid, gid, mode := captureOwnership(file)
runCtx, cancel := context.WithTimeout(ctx, 8*time.Second) runCtx, cancel := context.WithTimeout(ctx, 8*time.Second)
defer cancel() defer cancel()
cmd := exec.CommandContext(runCtx, "ssh-keygen", "-R", entry, "-f", file) cmd := exec.CommandContext(runCtx, "ssh-keygen", "-R", entry, "-f", file)
out, err := cmd.CombinedOutput() out, err := cmd.CombinedOutput()
restoreOwnership(file, file+".old", uid, gid, mode)
if err == nil { if err == nil {
logf(logger, "known_hosts repaired: removed %s from %s", entry, file) logf(logger, "known_hosts repaired: removed %s from %s", entry, file)
return return
@ -151,6 +155,36 @@ func removeKnownHostEntry(ctx context.Context, logger *log.Logger, file string,
logf(logger, "warning: known_hosts cleanup failed for %s in %s: %v: %s", entry, file, err, strings.TrimSpace(string(out))) logf(logger, "warning: known_hosts cleanup failed for %s in %s: %v: %s", entry, file, err, strings.TrimSpace(string(out)))
} }
func captureOwnership(path string) (int, int, os.FileMode) {
info, err := os.Stat(path)
if err != nil {
return -1, -1, 0
}
st, ok := info.Sys().(*syscall.Stat_t)
if !ok {
return -1, -1, info.Mode().Perm()
}
return int(st.Uid), int(st.Gid), info.Mode().Perm()
}
func restoreOwnership(path string, backupPath string, uid int, gid int, mode os.FileMode) {
if uid < 0 || gid < 0 {
return
}
for _, candidate := range []string{path, backupPath} {
if candidate == "" {
continue
}
if _, err := os.Stat(candidate); err != nil {
continue
}
_ = os.Chown(candidate, uid, gid)
if mode != 0 {
_ = os.Chmod(candidate, mode)
}
}
}
func logf(logger *log.Logger, format string, args ...any) { func logf(logger *log.Logger, format string, args ...any) {
if logger != nil { if logger != nil {
logger.Printf(format, args...) logger.Printf(format, args...)