Files
nadir-agent/internal/auth/pamservice.go
T

52 lines
2.1 KiB
Go
Raw Normal View History

2026-06-22 16:06:57 +02:00
package auth
import (
"fmt"
"os"
)
// PAMService is the name of the PAM service nadir authenticates against.
// It maps to /etc/pam.d/<PAMService>. We use a dedicated service rather than
// a stock one like "login" so we control exactly which modules run during
// authentication. See README.md ("PAM service") for the full rationale.
const PAMService = "nadir"
var pamServicePath = "/etc/pam.d/" + PAMService
// pamServiceContent is the minimal stack nadir needs: verify the password
// against /etc/shadow and confirm the account is valid. It deliberately omits
// pam_fprintd (blocks ~30s waiting for a fingerprint swipe that never comes),
// pam_systemd, pam_env, and the rest of the distro's login stack.
const pamServiceContent = `#%PAM-1.0
# Managed by nadir. Do not rely on hand edits surviving - nadir recreates this
# file on startup only if it is missing. Minimal auth stack: verify the
# password against /etc/shadow and confirm the account is valid. Deliberately
# omits pam_fprintd (blocks ~30s on a fingerprint swipe), pam_systemd, pam_env.
auth required pam_unix.so
account required pam_unix.so
`
// EnsurePAMService writes the PAM service file if it is missing. nadir already
// runs as root (pam_unix needs to read /etc/shadow), so it can install its own
// PAM config rather than relying on a separate install step.
//
// It will not overwrite an existing file: an admin who has customized
// /etc/pam.d/nadir keeps their version. Returns an error only on a real I/O
// problem so main can fail loudly instead of later looking like bad
// credentials (a missing file falls through to pam_deny via /etc/pam.d/other).
func EnsurePAMService() error {
switch _, err := os.Stat(pamServicePath); {
case err == nil:
return nil // already present - leave admin customizations intact
case os.IsNotExist(err):
// fall through and create it
default:
return fmt.Errorf("stat %s: %w", pamServicePath, err)
}
if err := os.WriteFile(pamServicePath, []byte(pamServiceContent), 0644); err != nil {
return fmt.Errorf("write %s: %w (need root, and /etc/pam.d must be writable)", pamServicePath, err)
}
return nil
}