From f34d90f1a86720c407bb46391a04b38484def22f Mon Sep 17 00:00:00 2001 From: The_miro Date: Mon, 18 May 2026 11:45:04 +0200 Subject: [PATCH] setup: add dialog TUI to freeipa-client module for enrollment Presents a Cyberqueer-themed menu after package install: - Answerfile: prompts for path (defaults to FreeipaAnsible/freeipa-client-answerfile.json), offers to create one with defaults if it doesn't exist - Manual: dialog inputboxes for domain, realm, server, hostname, principal, passwordbox for the admin password, yes/no for mkhomedir/sudo/dns/fido2 - Skip: prints post-install hints Falls back to ipa-client-install directly if freeipa-client.sh is not available (standalone install outside the dotfiles repo). Co-Authored-By: Claude Sonnet 4.6 --- .../optional-Modules/apps/freeipa-client.sh | 239 ++++++++++++++++-- 1 file changed, 221 insertions(+), 18 deletions(-) diff --git a/setup/modules/optional-Modules/apps/freeipa-client.sh b/setup/modules/optional-Modules/apps/freeipa-client.sh index 555819c..219fdce 100755 --- a/setup/modules/optional-Modules/apps/freeipa-client.sh +++ b/setup/modules/optional-Modules/apps/freeipa-client.sh @@ -1,39 +1,242 @@ #!/bin/bash set -euo pipefail -# FreeIPA client — installs client packages and optionally enrolls this host. -# Packages: sssd + cyrus-sasl-gssapi from pacman; freeipa-client (AUR) for -# ipa-client-install, ipa-getkeytab, etc. +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +FREEIPA_DIR="$SCRIPT_DIR/../../FreeipaAnsible" +CLIENT_SCRIPT="$FREEIPA_DIR/freeipa-client.sh" +DEFAULT_AF="$FREEIPA_DIR/freeipa-client-answerfile.json" -PACMAN_PKGS=(sssd cyrus-sasl-gssapi openldap krb5 oddjob) -AUR_PKGS=(freeipa-client) +# Defaults — match freeipa-client-answerfile.json (sed-replaced by server installer) +DEF_DOMAIN="freeipa.abdelbaki.eu" +DEF_REALM="FREEIPA.ABDELBAKI.EU" +DEF_SERVER="freeipa.abdelbaki.eu" +# ── Packages ────────────────────────────────────────────────────────────────── echo "[+] Installing FreeIPA client packages..." -pacman -S --noconfirm --needed "${PACMAN_PKGS[@]}" +pacman -S --noconfirm --needed sssd cyrus-sasl-gssapi openldap krb5 oddjob if command -v yay &>/dev/null; then echo "[+] Installing freeipa-client (AUR)..." - yay -S --noconfirm --needed "${AUR_PKGS[@]}" + yay -S --noconfirm --needed freeipa-client else - echo "[!] yay not found — skipping AUR packages (freeipa-client)." - echo " Install yay, then run: yay -S --needed freeipa-client" + echo "[!] yay not found — skipping freeipa-client AUR package." + echo " Install yay then run: yay -S --needed freeipa-client" fi -# Enable sssd (without starting — host is not enrolled yet) systemctl enable sssd.service 2>/dev/null || true -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -CLIENT_ENROLL="$SCRIPT_DIR/../../FreeipaAnsible/freeipa-client.sh" +command -v dialog &>/dev/null || pacman -S --noconfirm --needed dialog +# ── Dialog theme ────────────────────────────────────────────────────────────── +if [[ -z "${DIALOGRC:-}" ]] || [[ ! -f "${DIALOGRC:-/dev/null}" ]]; then + _TMP_D=$(mktemp -d) + trap 'rm -rf "$_TMP_D"' EXIT + export DIALOGRC="$_TMP_D/dialogrc" + cat > "$DIALOGRC" <<'RCEOF' +use_shadow = ON +use_colors = ON +screen_color = (BLACK,BLACK,ON) +shadow_color = (BLACK,BLACK,ON) +title_color = (MAGENTA,BLACK,ON) +border_color = (MAGENTA,BLACK,ON) +button_active_color = (BLACK,MAGENTA,ON) +button_inactive_color = (WHITE,BLACK,OFF) +button_key_active_color = (BLACK,CYAN,ON) +button_key_inactive_color = (CYAN,BLACK,ON) +button_label_active_color = (BLACK,MAGENTA,ON) +button_label_inactive_color = (WHITE,BLACK,OFF) +inputbox_color = (WHITE,BLACK,OFF) +inputbox_border_color = (MAGENTA,BLACK,ON) +menubox_color = (WHITE,BLACK,OFF) +menubox_border_color = (MAGENTA,BLACK,ON) +item_color = (WHITE,BLACK,OFF) +item_selected_color = (BLACK,MAGENTA,ON) +tag_color = (CYAN,BLACK,ON) +tag_selected_color = (BLACK,CYAN,ON) +tag_key_color = (CYAN,BLACK,ON) +tag_key_selected_color = (BLACK,CYAN,ON) +check_color = (WHITE,BLACK,OFF) +check_selected_color = (BLACK,MAGENTA,ON) +uarrow_color = (MAGENTA,BLACK,ON) +darrow_color = (MAGENTA,BLACK,ON) +RCEOF +fi + +BT="FreeIPA Client Setup" +T=$(mktemp); trap 'rm -f "$T"' EXIT + +d() { dialog --backtitle "$BT" "$@" 3>&1 1>&2 2>&3; } +input(){ d --title " $1 " --inputbox "$2" 10 64 "$3"; } +pass() { d --title " $1 " --passwordbox "$2" 10 64; } +yn() { d --title " $1 " --yesno "$2" 7 64; } +msg() { d --title " FreeIPA Client " --msgbox "$1" 10 64; } + +# ── Enrollment choice ───────────────────────────────────────────────────────── +CHOICE=$(d --title " FreeIPA Client Enrollment " \ + --menu "\n Packages installed.\n How would you like to enroll this host?\n" \ + 13 64 3 \ + "answerfile" "Use a JSON answerfile" \ + "manual" "Enter enrollment data manually" \ + "skip" "Skip — enroll later") || CHOICE="skip" + +# ── Helpers ─────────────────────────────────────────────────────────────────── +run_enroll() { + local args=("$@") + if [[ -x "$CLIENT_SCRIPT" ]]; then + exec "$CLIENT_SCRIPT" "${args[@]}" + else + # Fall back to ipa-client-install directly + local cmd=(ipa-client-install --unattended) + local dom="" rlm="" srv="" hst="" pri="admin" pwd="" ntp="" + local mkhomedir=true sudo_=true dns=true fido2=false + declare -a fido2_users=() + + for ((i=0; i<${#args[@]}; i++)); do + case "${args[$i]}" in + --domain) dom="${args[$((i+1))]}"; ((i++)) ;; + --realm) rlm="${args[$((i+1))]}"; ((i++)) ;; + --server) srv="${args[$((i+1))]}"; ((i++)) ;; + --hostname) hst="${args[$((i+1))]}"; ((i++)) ;; + --principal) pri="${args[$((i+1))]}"; ((i++)) ;; + --password) pwd="${args[$((i+1))]}"; ((i++)) ;; + --ntp-server) ntp="${args[$((i+1))]}"; ((i++)) ;; + --no-mkhomedir) mkhomedir=false ;; + --no-sudo) sudo_=false ;; + --no-dns-update) dns=false ;; + --fido2) fido2=true ;; + --fido2-user) fido2_users+=("${args[$((i+1))]}"); ((i++)) ;; + esac + done + + [[ -n "$dom" ]] && cmd+=(--domain "$dom") + [[ -n "$rlm" ]] && cmd+=(--realm "$rlm") + [[ -n "$srv" ]] && cmd+=(--server "$srv") + [[ -n "$hst" ]] && cmd+=(--hostname "$hst") + [[ -n "$ntp" ]] && cmd+=(--ntp-server "$ntp") + cmd+=(--principal "$pri" --password "$pwd") + $mkhomedir && cmd+=(--mkhomedir) || cmd+=(--no-mkhomedir) + $sudo_ && cmd+=(--enable-dns-updates) || true + ! $dns && cmd+=(--no-dns-update) || true + exec "${cmd[@]}" + fi +} + +# ── Answerfile mode ─────────────────────────────────────────────────────────── +if [[ "$CHOICE" == "answerfile" ]]; then + AF_PATH=$(input "Answerfile path" \ + "Path to the JSON answerfile:" \ + "$DEFAULT_AF") || { msg " Enrollment cancelled."; exit 0; } + + [[ -z "$AF_PATH" ]] && AF_PATH="$DEFAULT_AF" + + if [[ ! -f "$AF_PATH" ]]; then + if yn "Create answerfile" \ + " '$AF_PATH' does not exist.\n Create it with default values?"; then + mkdir -p "$(dirname "$AF_PATH")" + cat > "$AF_PATH" </dev/null || hostname) + HOST=$(input "This Host FQDN" "Hostname to register (leave blank = current):" \ + "$DEF_HOST") || HOST="$DEF_HOST" + + PRINCIPAL=$(input "Admin Principal" "IPA admin principal:" "admin") || PRINCIPAL="admin" + PRINCIPAL="${PRINCIPAL:-admin}" + + PASSWORD=$(pass "Admin Password" "Password for $PRINCIPAL@$REALM:") \ + || { msg " Enrollment cancelled."; exit 0; } + [[ -z "$PASSWORD" ]] && { msg " Password is required."; exit 1; } + + NTP=$(input "NTP Server" "NTP server (blank to skip):" "") || NTP="" + + ARGS=( + --domain "$DOMAIN" + --realm "$REALM" + --server "$SERVER" + --hostname "$HOST" + --principal "$PRINCIPAL" + --password "$PASSWORD" + ) + [[ -n "$NTP" ]] && ARGS+=(--ntp-server "$NTP") + + yn "Home Directories" " Auto-create home directories on first login?" \ + && true || ARGS+=(--no-mkhomedir) + + yn "Sudo via SSSD" " Configure sudo rules via SSSD?" \ + && true || ARGS+=(--no-sudo) + + yn "DNS Update" " Register this host's IP in IPA DNS?" \ + && true || ARGS+=(--no-dns-update) + + if yn "FIDO2" " Enable FIDO2/WebAuthn authentication?"; then + ARGS+=(--fido2) + FIDO2_USERS=$(input "FIDO2 Users" \ + "Usernames to enable FIDO2 for (comma-separated, blank = all):" "") \ + || FIDO2_USERS="" + if [[ -n "$FIDO2_USERS" ]]; then + IFS=',' read -ra _U <<< "$FIDO2_USERS" + for u in "${_U[@]}"; do + u="${u// /}" + [[ -n "$u" ]] && ARGS+=(--fido2-user "$u") + done + fi + fi + + clear + run_enroll "${ARGS[@]}" +fi + +# ── Skip ────────────────────────────────────────────────────────────────────── echo "" echo "[✓] FreeIPA client packages installed." echo "" -echo " To enroll this host, run one of:" -echo " ipa-client-install --domain= --server= --principal=admin" -if [[ -f "$CLIENT_ENROLL" ]]; then - echo " $CLIENT_ENROLL --interactive" - echo " $CLIENT_ENROLL --answerfile /path/to/answerfile.json" +echo " To enroll later, run one of:" +if [[ -x "$CLIENT_SCRIPT" ]]; then + echo " $CLIENT_SCRIPT --interactive" + echo " $CLIENT_SCRIPT --answerfile $DEFAULT_AF" +else + echo " ipa-client-install --domain= --server= --principal=admin" fi echo "" -echo " After enrollment, enable auto-home-dir creation:" +echo " After enrollment:" echo " authselect select sssd with-mkhomedir --force"