BastionGuard/thirdparty/bastionguard-recovery-data/scripts/install-grub-entry.sh
specialworld83 f0f913a209 Release 2.0
2026-07-15 10:52:22 +02:00

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 "$@"