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 <noreply@anthropic.com>
main
The_miro 2026-05-18 11:45:04 +02:00
parent c51af40fce
commit f34d90f1a8
1 changed files with 221 additions and 18 deletions

View File

@ -1,39 +1,242 @@
#!/bin/bash #!/bin/bash
set -euo pipefail set -euo pipefail
# FreeIPA client — installs client packages and optionally enrolls this host. SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Packages: sssd + cyrus-sasl-gssapi from pacman; freeipa-client (AUR) for FREEIPA_DIR="$SCRIPT_DIR/../../FreeipaAnsible"
# ipa-client-install, ipa-getkeytab, etc. CLIENT_SCRIPT="$FREEIPA_DIR/freeipa-client.sh"
DEFAULT_AF="$FREEIPA_DIR/freeipa-client-answerfile.json"
PACMAN_PKGS=(sssd cyrus-sasl-gssapi openldap krb5 oddjob) # Defaults — match freeipa-client-answerfile.json (sed-replaced by server installer)
AUR_PKGS=(freeipa-client) DEF_DOMAIN="freeipa.abdelbaki.eu"
DEF_REALM="FREEIPA.ABDELBAKI.EU"
DEF_SERVER="freeipa.abdelbaki.eu"
# ── Packages ──────────────────────────────────────────────────────────────────
echo "[+] Installing FreeIPA client 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 if command -v yay &>/dev/null; then
echo "[+] Installing freeipa-client (AUR)..." echo "[+] Installing freeipa-client (AUR)..."
yay -S --noconfirm --needed "${AUR_PKGS[@]}" yay -S --noconfirm --needed freeipa-client
else else
echo "[!] yay not found — skipping AUR packages (freeipa-client)." echo "[!] yay not found — skipping freeipa-client AUR package."
echo " Install yay, then run: yay -S --needed freeipa-client" echo " Install yay then run: yay -S --needed freeipa-client"
fi fi
# Enable sssd (without starting — host is not enrolled yet)
systemctl enable sssd.service 2>/dev/null || true systemctl enable sssd.service 2>/dev/null || true
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" command -v dialog &>/dev/null || pacman -S --noconfirm --needed dialog
CLIENT_ENROLL="$SCRIPT_DIR/../../FreeipaAnsible/freeipa-client.sh"
# ── 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" <<AFEOF
{
"domain": "$DEF_DOMAIN",
"realm": "$DEF_REALM",
"server": "$DEF_SERVER",
"hostname": "",
"principal": "admin",
"password": "",
"mkhomedir": true,
"sudo": true,
"dns_update": true,
"ntp_server": "",
"fido2": false,
"fido2_users": []
}
AFEOF
msg " Created: $AF_PATH\n\n Edit it to match your environment,\n then re-run the FreeIPA Client module to enroll."
exit 0
else
msg " Provide an existing answerfile and re-run."
exit 0
fi
fi
clear
run_enroll --answerfile "$AF_PATH"
fi
# ── Manual mode ───────────────────────────────────────────────────────────────
if [[ "$CHOICE" == "manual" ]]; then
DOMAIN=$(input "IPA Domain" "FreeIPA domain:" "$DEF_DOMAIN") \
|| { msg " Enrollment cancelled."; exit 0; }
DOMAIN="${DOMAIN:-$DEF_DOMAIN}"
DEF_REALM_CALC="${DOMAIN^^}"
REALM=$(input "Kerberos Realm" "Kerberos realm (usually domain uppercased):" \
"$DEF_REALM_CALC") || REALM="$DEF_REALM_CALC"
REALM="${REALM:-$DEF_REALM_CALC}"
SERVER=$(input "IPA Server" "FreeIPA server FQDN:" "$DOMAIN") \
|| { msg " Enrollment cancelled."; exit 0; }
SERVER="${SERVER:-$DOMAIN}"
DEF_HOST=$(hostname -f 2>/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 ""
echo "[✓] FreeIPA client packages installed." echo "[✓] FreeIPA client packages installed."
echo "" echo ""
echo " To enroll this host, run one of:" echo " To enroll later, run one of:"
echo " ipa-client-install --domain=<domain> --server=<server> --principal=admin" if [[ -x "$CLIENT_SCRIPT" ]]; then
if [[ -f "$CLIENT_ENROLL" ]]; then echo " $CLIENT_SCRIPT --interactive"
echo " $CLIENT_ENROLL --interactive" echo " $CLIENT_SCRIPT --answerfile $DEFAULT_AF"
echo " $CLIENT_ENROLL --answerfile /path/to/answerfile.json" else
echo " ipa-client-install --domain=<domain> --server=<server> --principal=admin"
fi fi
echo "" echo ""
echo " After enrollment, enable auto-home-dir creation:" echo " After enrollment:"
echo " authselect select sssd with-mkhomedir --force" echo " authselect select sssd with-mkhomedir --force"