508 lines
15 KiB
Bash
508 lines
15 KiB
Bash
#!/usr/bin/env bash
|
|
# =============================================================================
|
|
# install-grub-entry.sh
|
|
#
|
|
# Installa la voce GRUB per BastionGuard Recovery.
|
|
# Supporta:
|
|
# - BIOS / Legacy
|
|
# - UEFI senza Secure Boot
|
|
# - UEFI + shim signed + MOK
|
|
# - UEFI + custom Secure Boot keys
|
|
#
|
|
# SECUREBOOT_MODE:
|
|
# auto -> rileva e sceglie shim/custom/off
|
|
# shim -> forza shim + grub signed + MOK
|
|
# custom -> forza custom EFI signing chain
|
|
# off -> nessuna chain SB richiesta
|
|
#
|
|
# CUSTOM_SIGN_BACKEND:
|
|
# auto -> usa sbctl se presente, altrimenti verifica passiva
|
|
# sbctl -> usa sbctl per verifiche/info su chain custom
|
|
# none -> nessun backend custom specifico
|
|
# =============================================================================
|
|
|
|
set -Eeuo pipefail
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Config
|
|
# -----------------------------------------------------------------------------
|
|
|
|
SECUREBOOT_MODE="${SECUREBOOT_MODE:-auto}" # auto | shim | custom | off
|
|
CUSTOM_SIGN_BACKEND="${CUSTOM_SIGN_BACKEND:-auto}" # auto | sbctl | none
|
|
|
|
GRUB_SOURCE="/usr/share/bastionguard-backup/grub/42_bastionguard-recovery"
|
|
GRUB_DEST="/etc/grub.d/42_bastionguard-recovery"
|
|
|
|
RECOVERY_DIR="/boot/bastionguard-recovery"
|
|
LIVE_DIR="$RECOVERY_DIR/live"
|
|
|
|
KERNEL_FILE="$RECOVERY_DIR/vmlinuz"
|
|
INITRD_FILE="$RECOVERY_DIR/initrd.img"
|
|
SQUASHFS_FILE="$LIVE_DIR/filesystem.squashfs"
|
|
SIZE_FILE="$LIVE_DIR/filesystem.size"
|
|
|
|
EFI_BOOT_DIR="$RECOVERY_DIR/EFI/BOOT"
|
|
EFI_DEBIAN_DIR="$RECOVERY_DIR/EFI/debian"
|
|
EFI_GRUB_DIR="$RECOVERY_DIR/grub"
|
|
|
|
BOOTX64_EFI="$EFI_BOOT_DIR/BOOTx64.EFI"
|
|
GRUBX64_EFI="$EFI_BOOT_DIR/grubx64.efi"
|
|
MMX64_EFI="$EFI_BOOT_DIR/mmx64.efi"
|
|
EFI_BOOT_CFG="$EFI_BOOT_DIR/grub.cfg"
|
|
EFI_DEBIAN_CFG="$EFI_DEBIAN_DIR/grub.cfg"
|
|
MAIN_GRUB_CFG="$EFI_GRUB_DIR/grub.cfg"
|
|
ROOT_STUB_CFG="$RECOVERY_DIR/grub.cfg"
|
|
|
|
SECUREBOOT_DIR="/etc/bastionguard-backup/secureboot"
|
|
MOK_DER="$SECUREBOOT_DIR/MOK.der"
|
|
|
|
CUSTOM_SB_DIR="/etc/bastionguard-backup/custom-secureboot"
|
|
CUSTOM_EFI_DER="$CUSTOM_SB_DIR/DB.der"
|
|
CUSTOM_EFI_CRT="$CUSTOM_SB_DIR/DB.crt"
|
|
CUSTOM_EFI_KEY="$CUSTOM_SB_DIR/DB.key"
|
|
|
|
LOG_PREFIX="[BastionGuard Recovery]"
|
|
|
|
SB_FIRMWARE_MODE="bios"
|
|
SB_ENABLED="no"
|
|
SB_HAS_MS_KEYS="no"
|
|
SB_HAS_CUSTOM_KEYS="no"
|
|
SB_EFFECTIVE_MODE="off"
|
|
CUSTOM_SIGN_BACKEND_EFFECTIVE="none"
|
|
|
|
GRUB_CFG_TARGET=""
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Logging / errors
|
|
# -----------------------------------------------------------------------------
|
|
|
|
log() {
|
|
echo "$LOG_PREFIX [INFO] $*"
|
|
}
|
|
|
|
warn() {
|
|
echo "$LOG_PREFIX [WARN] $*" >&2
|
|
}
|
|
|
|
die() {
|
|
echo "$LOG_PREFIX [ERROR] $*" >&2
|
|
exit 1
|
|
}
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Helpers
|
|
# -----------------------------------------------------------------------------
|
|
|
|
require_root() {
|
|
[ "$EUID" -eq 0 ] || die "Eseguire come root."
|
|
}
|
|
|
|
require_file() {
|
|
local f="$1"
|
|
[ -f "$f" ] || die "File non trovato: $f"
|
|
}
|
|
|
|
optional_file_info() {
|
|
local f="$1"
|
|
if [ -f "$f" ]; then
|
|
echo " $f ($(du -sh "$f" | cut -f1))"
|
|
fi
|
|
}
|
|
|
|
detect_firmware_mode() {
|
|
if [ -d /sys/firmware/efi ]; then
|
|
SB_FIRMWARE_MODE="uefi"
|
|
else
|
|
SB_FIRMWARE_MODE="bios"
|
|
fi
|
|
}
|
|
|
|
detect_secure_boot_state() {
|
|
SB_ENABLED="no"
|
|
|
|
[ "$SB_FIRMWARE_MODE" = "uefi" ] || return 0
|
|
|
|
if command -v mokutil >/dev/null 2>&1; then
|
|
if mokutil --sb-state 2>/dev/null | grep -qi "SecureBoot enabled"; then
|
|
SB_ENABLED="yes"
|
|
return 0
|
|
fi
|
|
if mokutil --sb-state 2>/dev/null | grep -qi "SecureBoot disabled"; then
|
|
SB_ENABLED="no"
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
local sb_var
|
|
sb_var="$(find /sys/firmware/efi/efivars -maxdepth 1 -name 'SecureBoot-*' 2>/dev/null | head -n1 || true)"
|
|
if [ -n "$sb_var" ] && [ -r "$sb_var" ]; then
|
|
local value
|
|
value="$(od -An -t u1 -j4 -N1 "$sb_var" 2>/dev/null | tr -d ' ')"
|
|
if [ "${value:-0}" = "1" ]; then
|
|
SB_ENABLED="yes"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
detect_microsoft_keys() {
|
|
SB_HAS_MS_KEYS="no"
|
|
[ "$SB_FIRMWARE_MODE" = "uefi" ] || return 0
|
|
|
|
if command -v efi-readvar >/dev/null 2>&1; then
|
|
local tmp_db tmp_kek
|
|
tmp_db="$(mktemp)"
|
|
tmp_kek="$(mktemp)"
|
|
|
|
efi-readvar -v db >"$tmp_db" 2>/dev/null || true
|
|
efi-readvar -v KEK >"$tmp_kek" 2>/dev/null || true
|
|
|
|
if grep -Eqi 'Microsoft|Windows UEFI CA|Microsoft Corporation UEFI' "$tmp_db" "$tmp_kek"; then
|
|
SB_HAS_MS_KEYS="yes"
|
|
fi
|
|
|
|
rm -f "$tmp_db" "$tmp_kek"
|
|
else
|
|
warn "efi-readvar non trovato sull'host; rilevamento chiavi Microsoft limitato."
|
|
fi
|
|
}
|
|
|
|
detect_custom_keys() {
|
|
if [ -f "$CUSTOM_EFI_DER" ] || [ -f "$CUSTOM_EFI_CRT" ] || [ -f "$CUSTOM_EFI_KEY" ]; then
|
|
SB_HAS_CUSTOM_KEYS="yes"
|
|
else
|
|
SB_HAS_CUSTOM_KEYS="no"
|
|
fi
|
|
}
|
|
|
|
detect_custom_sign_backend() {
|
|
case "$CUSTOM_SIGN_BACKEND" in
|
|
sbctl)
|
|
command -v sbctl >/dev/null 2>&1 || die "CUSTOM_SIGN_BACKEND=sbctl ma sbctl non è installato."
|
|
CUSTOM_SIGN_BACKEND_EFFECTIVE="sbctl"
|
|
;;
|
|
none)
|
|
CUSTOM_SIGN_BACKEND_EFFECTIVE="none"
|
|
;;
|
|
auto)
|
|
if command -v sbctl >/dev/null 2>&1; then
|
|
CUSTOM_SIGN_BACKEND_EFFECTIVE="sbctl"
|
|
else
|
|
CUSTOM_SIGN_BACKEND_EFFECTIVE="none"
|
|
fi
|
|
;;
|
|
*)
|
|
die "CUSTOM_SIGN_BACKEND non valido: $CUSTOM_SIGN_BACKEND"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
decide_secureboot_mode() {
|
|
detect_firmware_mode
|
|
detect_secure_boot_state
|
|
detect_microsoft_keys
|
|
detect_custom_keys
|
|
detect_custom_sign_backend
|
|
|
|
log "Firmware mode : $SB_FIRMWARE_MODE"
|
|
log "Secure Boot : $SB_ENABLED"
|
|
log "Microsoft keys : $SB_HAS_MS_KEYS"
|
|
log "Custom cert : $SB_HAS_CUSTOM_KEYS"
|
|
log "Requested mode : $SECUREBOOT_MODE"
|
|
log "Custom backend : $CUSTOM_SIGN_BACKEND_EFFECTIVE"
|
|
|
|
if [ "$SB_FIRMWARE_MODE" != "uefi" ]; then
|
|
SB_EFFECTIVE_MODE="off"
|
|
log "Effective mode : off (BIOS/Legacy)"
|
|
return 0
|
|
fi
|
|
|
|
case "$SECUREBOOT_MODE" in
|
|
off)
|
|
SB_EFFECTIVE_MODE="off"
|
|
;;
|
|
shim)
|
|
SB_EFFECTIVE_MODE="shim"
|
|
;;
|
|
custom)
|
|
SB_EFFECTIVE_MODE="custom"
|
|
;;
|
|
auto)
|
|
if [ "$SB_ENABLED" != "yes" ]; then
|
|
SB_EFFECTIVE_MODE="off"
|
|
elif [ "$SB_HAS_MS_KEYS" = "yes" ]; then
|
|
SB_EFFECTIVE_MODE="shim"
|
|
elif [ "$SB_HAS_CUSTOM_KEYS" = "yes" ] || [ "$CUSTOM_SIGN_BACKEND_EFFECTIVE" = "sbctl" ]; then
|
|
SB_EFFECTIVE_MODE="custom"
|
|
else
|
|
die "Secure Boot attivo ma nessuna chain valida rilevata (né Microsoft/shim né custom)."
|
|
fi
|
|
;;
|
|
*)
|
|
die "SECUREBOOT_MODE non valido: $SECUREBOOT_MODE"
|
|
;;
|
|
esac
|
|
|
|
log "Effective mode : $SB_EFFECTIVE_MODE"
|
|
}
|
|
|
|
check_recovery_files() {
|
|
echo "[1/5] Verifica file recovery..."
|
|
|
|
require_file "$KERNEL_FILE"
|
|
require_file "$INITRD_FILE"
|
|
require_file "$SQUASHFS_FILE"
|
|
|
|
if [ ! -f "$SIZE_FILE" ]; then
|
|
warn "filesystem.size non trovato — continuo comunque."
|
|
fi
|
|
|
|
echo " kernel -> $KERNEL_FILE ($(du -sh "$KERNEL_FILE" | cut -f1))"
|
|
echo " initrd -> $INITRD_FILE ($(du -sh "$INITRD_FILE" | cut -f1))"
|
|
echo " squashfs -> $SQUASHFS_FILE ($(du -sh "$SQUASHFS_FILE" | cut -f1))"
|
|
[ -f "$SIZE_FILE" ] && echo " size -> $SIZE_FILE ($(du -sh "$SIZE_FILE" | cut -f1))"
|
|
}
|
|
|
|
install_grub_script() {
|
|
echo "[2/5] Installazione script GRUB..."
|
|
|
|
require_file "$GRUB_SOURCE"
|
|
install -Dm755 "$GRUB_SOURCE" "$GRUB_DEST"
|
|
echo " installato: $GRUB_DEST"
|
|
}
|
|
|
|
check_kernel_signature_generic() {
|
|
if command -v sbverify >/dev/null 2>&1; then
|
|
if sbverify --list "$KERNEL_FILE" >/dev/null 2>&1; then
|
|
echo " [OK] Kernel firmato/verificabile con sbverify."
|
|
else
|
|
warn "Kernel non firmato o firma non verificabile con sbverify."
|
|
fi
|
|
else
|
|
warn "sbverify non trovato, salto verifica firma kernel."
|
|
fi
|
|
}
|
|
|
|
check_kernel_signature_sbctl() {
|
|
if ! command -v sbctl >/dev/null 2>&1; then
|
|
warn "sbctl non trovato, salto verifica kernel via sbctl."
|
|
return 0
|
|
fi
|
|
|
|
if sbctl verify "$KERNEL_FILE" >/dev/null 2>&1; then
|
|
echo " [OK] Kernel verificato da sbctl."
|
|
else
|
|
warn "Kernel non verificato da sbctl."
|
|
fi
|
|
}
|
|
|
|
check_efi_binary_signature_sbctl() {
|
|
local f="$1"
|
|
[ -f "$f" ] || return 0
|
|
|
|
if ! command -v sbctl >/dev/null 2>&1; then
|
|
return 0
|
|
fi
|
|
|
|
if sbctl verify "$f" >/dev/null 2>&1; then
|
|
echo " [OK] Verificato da sbctl: $f"
|
|
else
|
|
warn "Non verificato da sbctl: $f"
|
|
fi
|
|
}
|
|
|
|
check_efi_layout_off() {
|
|
echo " Modalità EFI: off"
|
|
[ -f "$BOOTX64_EFI" ] || warn "BOOTx64.EFI non trovato: $BOOTX64_EFI"
|
|
[ -f "$GRUBX64_EFI" ] || warn "grubx64.efi non trovato: $GRUBX64_EFI"
|
|
}
|
|
|
|
check_efi_layout_shim() {
|
|
echo " Modalità EFI: shim"
|
|
|
|
require_file "$BOOTX64_EFI"
|
|
require_file "$GRUBX64_EFI"
|
|
|
|
echo " [OK] Chain shim trovata:"
|
|
optional_file_info "$BOOTX64_EFI"
|
|
optional_file_info "$GRUBX64_EFI"
|
|
optional_file_info "$MMX64_EFI"
|
|
|
|
if [ -f "$MOK_DER" ]; then
|
|
echo " [OK] Certificato MOK trovato: $MOK_DER"
|
|
echo
|
|
echo " Se la MOK non è registrata nel firmware:"
|
|
echo " mokutil --import $MOK_DER"
|
|
echo " (poi riavvio e conferma in MokManager)"
|
|
else
|
|
warn "Certificato MOK non trovato: $MOK_DER"
|
|
fi
|
|
}
|
|
|
|
check_efi_layout_custom() {
|
|
echo " Modalità EFI: custom"
|
|
|
|
require_file "$BOOTX64_EFI"
|
|
require_file "$GRUBX64_EFI"
|
|
|
|
echo " [OK] Chain custom trovata:"
|
|
optional_file_info "$BOOTX64_EFI"
|
|
optional_file_info "$GRUBX64_EFI"
|
|
|
|
if [ -f "$CUSTOM_EFI_DER" ]; then
|
|
echo " [OK] Certificato custom trovato: $CUSTOM_EFI_DER"
|
|
else
|
|
warn "Certificato custom DER non trovato: $CUSTOM_EFI_DER"
|
|
fi
|
|
|
|
if [ "$CUSTOM_SIGN_BACKEND_EFFECTIVE" = "sbctl" ]; then
|
|
echo " Backend custom: sbctl"
|
|
check_kernel_signature_sbctl
|
|
check_efi_binary_signature_sbctl "$BOOTX64_EFI"
|
|
check_efi_binary_signature_sbctl "$GRUBX64_EFI"
|
|
else
|
|
check_kernel_signature_generic
|
|
fi
|
|
}
|
|
|
|
check_efi_layout_configs() {
|
|
[ -f "$EFI_BOOT_CFG" ] || warn "Stub EFI BOOT mancante: $EFI_BOOT_CFG"
|
|
[ -f "$EFI_DEBIAN_CFG" ] || warn "Stub EFI debian mancante: $EFI_DEBIAN_CFG"
|
|
[ -f "$MAIN_GRUB_CFG" ] || warn "Main grub.cfg mancante: $MAIN_GRUB_CFG"
|
|
[ -f "$ROOT_STUB_CFG" ] || warn "Stub root grub.cfg mancante: $ROOT_STUB_CFG"
|
|
}
|
|
|
|
check_secureboot_and_efi() {
|
|
echo "[3/5] Controllo Secure Boot / EFI..."
|
|
|
|
decide_secureboot_mode
|
|
|
|
if [ "$SB_FIRMWARE_MODE" != "uefi" ]; then
|
|
echo " Sistema BIOS/Legacy rilevato — nessuna verifica EFI necessaria."
|
|
return 0
|
|
fi
|
|
|
|
echo " Sistema UEFI rilevato."
|
|
|
|
case "$SB_EFFECTIVE_MODE" in
|
|
off)
|
|
check_kernel_signature_generic
|
|
check_efi_layout_off
|
|
;;
|
|
shim)
|
|
check_kernel_signature_generic
|
|
check_efi_layout_shim
|
|
;;
|
|
custom)
|
|
check_efi_layout_custom
|
|
;;
|
|
*)
|
|
die "Modalità Secure Boot effettiva non valida: $SB_EFFECTIVE_MODE"
|
|
;;
|
|
esac
|
|
|
|
check_efi_layout_configs
|
|
}
|
|
|
|
regenerate_grub_cfg() {
|
|
echo "[4/5] Rigenerazione grub.cfg..."
|
|
|
|
if command -v update-grub >/dev/null 2>&1; then
|
|
update-grub
|
|
if [ -f /boot/grub/grub.cfg ]; then
|
|
GRUB_CFG_TARGET="/boot/grub/grub.cfg"
|
|
fi
|
|
elif command -v grub-mkconfig >/dev/null 2>&1; then
|
|
if [ -d /boot/grub2 ]; then
|
|
grub-mkconfig -o /boot/grub2/grub.cfg
|
|
GRUB_CFG_TARGET="/boot/grub2/grub.cfg"
|
|
else
|
|
grub-mkconfig -o /boot/grub/grub.cfg
|
|
GRUB_CFG_TARGET="/boot/grub/grub.cfg"
|
|
fi
|
|
elif command -v grub2-mkconfig >/dev/null 2>&1; then
|
|
grub2-mkconfig -o /boot/grub2/grub.cfg
|
|
GRUB_CFG_TARGET="/boot/grub2/grub.cfg"
|
|
else
|
|
die "update-grub / grub-mkconfig / grub2-mkconfig non trovati."
|
|
fi
|
|
|
|
[ -n "$GRUB_CFG_TARGET" ] || warn "Impossibile determinare automaticamente il grub.cfg aggiornato."
|
|
}
|
|
|
|
verify_menu_entry() {
|
|
echo "[5/5] Verifica voce GRUB..."
|
|
|
|
local found=0
|
|
|
|
if [ -n "$GRUB_CFG_TARGET" ] && [ -f "$GRUB_CFG_TARGET" ]; then
|
|
if grep -q "BastionGuard Recovery" "$GRUB_CFG_TARGET"; then
|
|
echo " [OK] Voce BastionGuard Recovery presente in $GRUB_CFG_TARGET"
|
|
found=1
|
|
fi
|
|
fi
|
|
|
|
if [ "$found" -eq 0 ]; then
|
|
if [ -f /boot/grub/grub.cfg ] && grep -q "BastionGuard Recovery" /boot/grub/grub.cfg; then
|
|
echo " [OK] Voce trovata in /boot/grub/grub.cfg"
|
|
GRUB_CFG_TARGET="/boot/grub/grub.cfg"
|
|
found=1
|
|
elif [ -f /boot/grub2/grub.cfg ] && grep -q "BastionGuard Recovery" /boot/grub2/grub.cfg; then
|
|
echo " [OK] Voce trovata in /boot/grub2/grub.cfg"
|
|
GRUB_CFG_TARGET="/boot/grub2/grub.cfg"
|
|
found=1
|
|
fi
|
|
fi
|
|
|
|
if [ "$found" -eq 0 ]; then
|
|
warn "Voce BastionGuard Recovery non trovata nel grub.cfg — verificare manualmente."
|
|
fi
|
|
}
|
|
|
|
print_summary() {
|
|
echo
|
|
echo "========================================================"
|
|
echo " Installazione completata"
|
|
echo "========================================================"
|
|
echo " Recovery dir : $RECOVERY_DIR"
|
|
echo " Live dir : $LIVE_DIR"
|
|
[ -n "$GRUB_CFG_TARGET" ] && echo " grub.cfg : $GRUB_CFG_TARGET"
|
|
echo " SecureBoot mode : $SB_EFFECTIVE_MODE"
|
|
echo " Custom backend : $CUSTOM_SIGN_BACKEND_EFFECTIVE"
|
|
echo
|
|
echo " Al prossimo avvio apparirà la voce:"
|
|
echo " \"BastionGuard Recovery\""
|
|
echo
|
|
echo " Comandi utili:"
|
|
[ -n "$GRUB_CFG_TARGET" ] && echo " grep -n 'BastionGuard' $GRUB_CFG_TARGET"
|
|
echo " ls -lh $RECOVERY_DIR"
|
|
echo " ls -lh $LIVE_DIR"
|
|
if [ "$SB_FIRMWARE_MODE" = "uefi" ] && [ -d "$EFI_BOOT_DIR" ]; then
|
|
echo " ls -lh $EFI_BOOT_DIR"
|
|
fi
|
|
if [ "$SB_EFFECTIVE_MODE" = "shim" ] && [ -f "$MOK_DER" ]; then
|
|
echo " mokutil --import $MOK_DER"
|
|
fi
|
|
if [ "$SB_EFFECTIVE_MODE" = "custom" ] && [ "$CUSTOM_SIGN_BACKEND_EFFECTIVE" = "sbctl" ]; then
|
|
echo " sbctl verify $KERNEL_FILE"
|
|
echo " sbctl verify $BOOTX64_EFI"
|
|
echo " sbctl verify $GRUBX64_EFI"
|
|
fi
|
|
echo "========================================================"
|
|
}
|
|
|
|
main() {
|
|
require_root
|
|
|
|
echo "========================================================"
|
|
echo " BastionGuard Recovery — Installazione voce GRUB"
|
|
echo "========================================================"
|
|
|
|
check_recovery_files
|
|
install_grub_script
|
|
check_secureboot_and_efi
|
|
regenerate_grub_cfg
|
|
verify_menu_entry
|
|
print_summary
|
|
}
|
|
|
|
main "$@"
|