52 lines
2.1 KiB
Go
52 lines
2.1 KiB
Go
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
|
|
}
|