#!/bin/bash
# uhhm-corp-setup: enrol this machine as a uhhm corp device.
# Idempotent; run as root (via sudo, so the invoking user is known). Steps:
#   1. join the headscale VPN (vpn.uhhm.no) via tailscale
#   2. ensure the [uhhm] pacman repo + its signing key (shipped keyring)
#   3. wire kanidm into NSS and PAM, start kanidm-unixd
#   4. start cachefilesd (FS-Cache for the `fsc` NFS mounts)
#   5. create the invoking user's machine-local toolchain dirs in /var/local
#   6. (--with-nfs-home) automount /home from ergo over the VPN
#   7. (--with-basement) automount the basement archive from kasse
#
# --undo reverses 3, 6 and 7 (PAM, NSS, automounts) so the package can be
# removed without leaving a login stack that points at kanidm.
set -euo pipefail

[ "$(id -u)" -eq 0 ] || { echo "run as root" >&2; exit 1; }

PAM=/etc/pam.d/system-auth
AUTOMOUNTS=(home.automount home-bl-basement.automount)

undo() {
    echo "==> automounts: disabling ${AUTOMOUNTS[*]} (active mounts stay until reboot)"
    systemctl disable "${AUTOMOUNTS[@]}" 2>/dev/null || true

    echo "==> PAM: removing pam_kanidm from $PAM"
    if grep -q pam_kanidm "$PAM"; then
        cp "$PAM" "$PAM.pre-uhhm-undo"
        sed -i '/pam_kanidm\.so/d' "$PAM"
        echo "    removed (backup at $PAM.pre-uhhm-undo)"
    fi

    echo "==> NSS: removing kanidm from /etc/nsswitch.conf"
    sed -i -E '/^(passwd|group):/s/ kanidm\b//' /etc/nsswitch.conf

    echo "==> kanidm-unixd: stopping"
    systemctl disable --now kanidm-unixd-tasks kanidm-unixd 2>/dev/null || true

    echo "==> done. Left in place: tailscale (\`tailscale logout\` to leave the VPN)"
    echo "    and the [uhhm] repo in /etc/pacman.conf."
}

WITH_NFS_HOME=0
WITH_BASEMENT=0
for arg in "$@"; do
    case "$arg" in
        --with-nfs-home) WITH_NFS_HOME=1 ;;
        --with-basement) WITH_BASEMENT=1 ;;   # kasse archive; only once kasse is on the tailnet
        --undo) undo; exit 0 ;;
        *) echo "unknown option: $arg (use --with-nfs-home, --with-basement or --undo)" >&2; exit 1 ;;
    esac
done

echo "==> VPN: joining headscale at vpn.uhhm.no"
systemctl enable --now tailscaled
WANT="https://vpn.uhhm.no"
# Check the actual control plane, not just "tailscaled is running": a machine
# already logged into commercial Tailscale passes `tailscale status` yet is
# NOT on our VPN. Switching control planes needs --force-reauth.
HAVE=$(tailscale debug prefs 2>/dev/null | jq -r '.ControlURL // empty' 2>/dev/null || true)
if [ "$HAVE" != "$WANT" ]; then
    echo "    control plane is '${HAVE:-none}', moving to $WANT"
    # HEADSCALE_AUTHKEY (preauth key) makes this non-interactive; otherwise
    # it prints a Kanidm OIDC URL to complete in a browser. The key goes via
    # a private file, not argv, so it never shows up in `ps`.
    authargs=()
    if [ -n "${HEADSCALE_AUTHKEY:-}" ]; then
        keyfile=$(mktemp)
        trap 'rm -f "$keyfile"' EXIT
        printf '%s' "$HEADSCALE_AUTHKEY" >"$keyfile"
        authargs=(--auth-key "file:$keyfile")
    fi
    tailscale up --login-server="$WANT" --accept-dns --accept-routes --force-reauth \
        "${authargs[@]}"
else
    echo "    already on $WANT ($(tailscale ip -4 2>/dev/null | head -1))"
fi
tailscale status >/dev/null 2>&1 || { echo "VPN join did not complete" >&2; exit 1; }

echo "==> pacman: ensure the [uhhm] package registry + its signing key"
if ! grep -q '^\[uhhm\]' /etc/pacman.conf; then
    cat >> /etc/pacman.conf <<'PAC'

[uhhm]
SigLevel = Required DatabaseOptional
Server = https://project.uhhm.no/api/packages/bl/arch/$repo/$arch
PAC
    echo "    added [uhhm] repo"
fi
# The key ships in this package (/usr/share/pacman/keyrings/uhhm*), so no
# trust-on-first-use download; the install script also populates it.
pacman-key --populate uhhm >/dev/null \
    && echo "    uhhm registry key trusted" \
    || echo "    WARN: pacman-key --populate uhhm failed (is the keyring initialised?)"

echo "==> NSS: adding kanidm to /etc/nsswitch.conf"
for db in passwd group; do
    if ! grep -qE "^${db}:.*\bkanidm\b" /etc/nsswitch.conf; then
        sed -i "s/^${db}:.*/& kanidm/" /etc/nsswitch.conf
        echo "    ${db}: + kanidm"
    fi
done

echo "==> PAM: wiring pam_kanidm into system-auth"
if ! grep -q pam_kanidm "$PAM"; then
    cp "$PAM" "$PAM.pre-uhhm-corp"
    sed -i \
        -e '/^auth.*pam_unix.so/i auth       sufficient                  pam_kanidm.so ignore_unknown_user' \
        -e '/^account.*pam_unix.so/i account    [default=bad success=ok user_unknown=ignore] pam_kanidm.so' \
        -e '/^password.*pam_unix.so/i password   sufficient                  pam_kanidm.so ignore_unknown_user' \
        -e '/^session.*pam_unix.so/i session    optional                    pam_kanidm.so' \
        "$PAM"
    echo "    patched (backup at $PAM.pre-uhhm-corp)"
else
    echo "    already wired"
fi
# system-auth belongs to pambase; an upgrade that changes it lands as .pacnew
# WITHOUT our lines. Merging it naively drops kanidm from the login stack.
if [ -e "$PAM.pacnew" ]; then
    echo "    WARN: $PAM.pacnew exists. After merging it, re-run uhhm-corp-setup"
    echo "          to re-add the pam_kanidm lines."
fi

echo "==> kanidm-unixd"
systemctl enable --now kanidm-unixd kanidm-unixd-tasks

echo "==> NFS FS-Cache (fsc mounts cache locally; needed before the NFS home)"
install -dm700 /var/cache/fscache   # cachefilesd refuses to start without its cache dir
systemctl enable --now cachefilesd \
    || echo "    WARN: cachefilesd failed to start; NFS fsc caching disabled (continuing)"

# Machine-local, arch-specific toolchains. The shared fish config sets
# CARGO_HOME=/var/local/cargo, RUSTUP_HOME=/var/local/rustup and
# PNPM_HOME=/var/local/pnpm-<arch>, so on a mixed-arch fleet each machine
# keeps its own compiled toolchains outside the NFS home. ~/.local/bin stays
# roamed and is for arch-independent scripts only. These paths are shared by
# design (one toolchain per machine), owned by the user who ran the setup.
echo "==> machine-local toolchain dirs in /var/local"
if [ -n "${SUDO_USER:-}" ] && [ "$SUDO_USER" != root ]; then
    install -dm755 -o "$SUDO_USER" -g "$(id -g "$SUDO_USER")" \
        /var/local/cargo /var/local/rustup "/var/local/pnpm-$(uname -m)"
    echo "    owned by $SUDO_USER"
else
    echo "    skipped: run via sudo so the owning user is known"
fi

if [ "$WITH_NFS_HOME" -eq 1 ]; then
    echo "==> NFS home from ergo (shadows local /home!)"
    systemctl daemon-reload
    systemctl enable --now home.automount
fi
if [ "$WITH_BASEMENT" -eq 1 ]; then
    echo "==> basement archive automount from kasse"
    echo "    (only enable this when kasse is reliably on the tailnet)"
    systemctl daemon-reload
    systemctl enable --now home-bl-basement.automount
fi

echo "==> SSH: kanidm-authorised logins are configured (etc/ssh drop-ins)."
echo "    Each user should now give this machine its own key:  uhhm-ssh-enroll"
echo "    Break-glass: drop a local admin key in /etc/ssh/authorized_keys.d/<user>"
echo "    so the box stays reachable if kanidm or the NFS home are down at boot."
echo
echo "==> IMPORTANT: every corp user needs a Kanidm POSIX password (SEPARATE from"
echo "    their web password+TOTP), or pam_kanidm's account phase refuses ALL logins"
echo "    for that user here (even key-based SSH): 'administrator enforced password"
echo "    change'. Set it with:"
echo "        kanidm login -D <user> && kanidm person posix set-password <user>"
echo "==> done. Verify with: kanidm login -D <user>; getent passwd <user>"
