Pam diagnostic

This commit is contained in:
2026-07-14 00:26:05 -03:00
parent 8117f6ed11
commit 5ddca88147
2 changed files with 15 additions and 7 deletions
+4 -4
View File
@@ -2206,18 +2206,18 @@ func passwordCallback(meta ssh.ConnMetadata, pass []byte) (*ssh.Permissions, err
if !ok { if !ok {
importPAMUser(meta.User()) importPAMUser(meta.User())
} }
log.Printf("PAM: %q authenticated against /etc/shadow", meta.User()) pamLogf("PAM: %q authenticated against /etc/shadow", meta.User())
return nil, nil return nil, nil
} else { } else {
log.Printf("PAM: %q rejected by /etc/shadow: %v", meta.User(), err) pamLogf("PAM: %q rejected by /etc/shadow: %v", meta.User(), err)
} }
} else if !ok { } else if !ok {
log.Printf("PAM: %q is not a regular login account (needs an /etc/passwd entry with UID >= %d)", meta.User(), minLoginUID) pamLogf("PAM: %q is not a regular login account (needs an /etc/passwd entry with UID >= %d)", meta.User(), minLoginUID)
} }
} }
if !ok { if !ok {
log.Printf("auth: user %q rejected (no panel account and PAM did not accept it)", meta.User()) pamLogf("auth: user %q rejected (no panel account and PAM did not accept it)", meta.User())
return nil, fmt.Errorf("authentication failed") return nil, fmt.Errorf("authentication failed")
} }
+11 -3
View File
@@ -33,6 +33,14 @@ const (
var errNoSystemPassword = errors.New("account has no usable password") var errNoSystemPassword = errors.New("account has no usable password")
// pamLogger writes PAM auth diagnostics straight to stderr (captured by
// journald) so they remain visible even when "Quiet Logs" redirects the default
// logger to io.Discard. Use pamLogf for anything an operator needs to see when
// debugging why a system login was accepted or refused.
var pamLogger = log.New(os.Stderr, "", log.LstdFlags)
func pamLogf(format string, args ...interface{}) { pamLogger.Printf(format, args...) }
// pamAuthEnabled mirrors Config.PAMAuthEnabled and is toggled live on config // pamAuthEnabled mirrors Config.PAMAuthEnabled and is toggled live on config
// reload. Guarded atomically so passwordCallback can read it lock-free. // reload. Guarded atomically so passwordCallback can read it lock-free.
var pamAuthEnabled atomic.Bool var pamAuthEnabled atomic.Bool
@@ -50,10 +58,10 @@ func importPAMUser(username string) {
if !userMgr.AddIfAbsent(st) { if !userMgr.AddIfAbsent(st) {
return // already present in memory return // already present in memory
} }
log.Printf("PAM: auto-imported system user %s into the panel", username) pamLogf("PAM: auto-imported system user %s into the panel", username)
if statsStore != nil { if statsStore != nil {
if err := statsStore.UpsertUser(context.Background(), cfg); err != nil { if err := statsStore.UpsertUser(context.Background(), cfg); err != nil {
log.Printf("PAM: failed to persist auto-imported user %s: %v", username, err) pamLogf("PAM: failed to persist auto-imported user %s: %v", username, err)
} }
} }
} }
@@ -64,7 +72,7 @@ func importPAMUser(username string) {
func isRegularLoginUser(username string) bool { func isRegularLoginUser(username string) bool {
data, err := os.ReadFile(passwdFile) data, err := os.ReadFile(passwdFile)
if err != nil { if err != nil {
log.Printf("PAM: cannot read %s: %v", passwdFile, err) pamLogf("PAM: cannot read %s: %v", passwdFile, err)
return false return false
} }
for _, line := range strings.Split(string(data), "\n") { for _, line := range strings.Split(string(data), "\n") {