105 lines
3.1 KiB
Bash
Executable File
105 lines
3.1 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
## This early-setup hook finds a LUKS volume by looking for a partition with
|
|
## label "KEYSTORE". (Partition labels are supported on GPT and a few obsolete
|
|
## disklabel formats; see the "name" command in parted(8) for details.)
|
|
##
|
|
## If a KEYSTORE partition is found, the hook attempts repeatedly to unlock and
|
|
## mount the encrypted volume (read-only) at /etc/zfs/keys. If successful, this
|
|
## will allow ZFSBootMenu to automatically unlock any ZFS datasets that define
|
|
## the ZFS property
|
|
##
|
|
## keylocation=file:///etc/zfs/keys
|
|
##
|
|
## If the partition cannot be found, does not appear to be a LUKS volume or has
|
|
## already been activated, the hook will terminate and allow ZFSBootMenu to
|
|
## proceed with its ordinary startup process. Once the hook begins the unlock
|
|
## loop, it will not terminate until either the volume is successfully unlocked
|
|
## or the user presses Ctrl-C to abandon the attempts. After every failed
|
|
## unlock cycle, an emergency shell will be invoked to allow manual
|
|
## intervention; type `exit` in the shell to continue the unlock loop.
|
|
##
|
|
## Because this script is intended to provide unlock keys *before* ZFSBootMenu
|
|
## imports ZFS pools, it should be run as an early hook. To install, put this
|
|
## script somewhere, make sure it is executable, and add the path to the
|
|
## `zfsbootmenu_early_setup` space-separated list with, e.g.,
|
|
##
|
|
## zfsbootmenu_early_setup+=" <path to script> "
|
|
##
|
|
## in a dracut.conf(5) file inside the directory specified for the option
|
|
## `Global.DracutConfDir` in the ZFSBootMenu `config.yaml`.
|
|
|
|
sources=(
|
|
/lib/profiling-lib.sh
|
|
/etc/zfsbootmenu.conf
|
|
/lib/zfsbootmenu-core.sh
|
|
/lib/kmsg-log-lib.sh
|
|
/etc/profile
|
|
)
|
|
|
|
for src in "${sources[@]}"; do
|
|
# shellcheck disable=SC1090
|
|
if ! source "${src}" > /dev/null 2>&1 ; then
|
|
echo -e "\033[0;31mWARNING: ${src} was not sourced; unable to proceed\033[0m"
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
unset src sources
|
|
|
|
luks="/dev/disk/by-partlabel/KEYSTORE"
|
|
dm="/dev/mapper/KEYSTORE"
|
|
|
|
if [ ! -b "${luks}" ] ; then
|
|
zinfo "keystore device ${luks} does not exist"
|
|
exit
|
|
fi
|
|
|
|
if ! cryptsetup isLuks ${luks} >/dev/null 2>&1 ; then
|
|
zwarn "keystore device ${luks} missing LUKS partition header"
|
|
exit
|
|
fi
|
|
|
|
if cryptsetup status "${dm}" >/dev/null 2>&1 ; then
|
|
zinfo "${dm} already active, not continuing"
|
|
exit
|
|
fi
|
|
|
|
header="$( center_string "[CTRL-C] cancel luksOpen attempts" )"
|
|
|
|
while true; do
|
|
tput clear
|
|
colorize red "${header}\n\n"
|
|
|
|
cryptsetup --tries=5 luksOpen "${luks}" KEYSTORE
|
|
ret=$?
|
|
|
|
# successfully entered a passphrase
|
|
if [ "${ret}" -eq 0 ] ; then
|
|
mkdir -p /etc/zfs/keys
|
|
mount -r "${dm}" /etc/zfs/keys
|
|
zdebug "$(
|
|
cryptsetup status "${dm}"
|
|
mount | grep KEYSTORE
|
|
)"
|
|
exit
|
|
fi
|
|
|
|
# ctrl-c'd the process
|
|
if [ "${ret}" -eq 1 ] ; then
|
|
zdebug "canceled luksOpen attempts via SIGINT"
|
|
exit
|
|
fi
|
|
|
|
# failed all password attempts
|
|
if [ "${ret}" -eq 2 ] ; then
|
|
if timed_prompt -e "emergency shell" \
|
|
-r "continue unlock attempts" \
|
|
-p "Continuing in %0.2d seconds" ; then
|
|
continue
|
|
else
|
|
emergency_shell "unable to unlock LUKS partition"
|
|
fi
|
|
fi
|
|
done
|