Enable booting from nested encrypted datasets

- enable booting from nested encrypted datasets
- fix plymouth boot splash passphrase entry
- optimize unlock process

Co-authored-by: Kash Pande <kash@tripleback.net>
Co-authored-by: Matthew Thode <mthode@mthode.org>
Signed-off-by: Kash Pande <kash@tripleback.net>
Signed-off-by: Matthew Thode <mthode@mthode.org>
Closes #7214
This commit is contained in:
Kash Pande 2018-02-20 13:13:20 -05:00 committed by Brian Behlendorf
parent bf95a000c4
commit 7280d58197
3 changed files with 82 additions and 33 deletions

View File

@ -59,28 +59,13 @@ if import_pool "${ZFS_POOL}" ; then
# Load keys if we can or if we need to
if [ $(zpool list -H -o feature@encryption $(echo "${ZFS_POOL}" | awk -F\/ '{print $1}')) == 'active' ]; then
# if the root dataset has encryption enabled
if $(zfs list -H -o encryption "${ZFS_DATASET}" | grep -q -v off); then
# figure out where the root dataset has its key, the keylocation should not be none
while true; do
if [[ $(zfs list -H -o keylocation "${ZFS_DATASET}") == 'none' ]]; then
ZFS_DATASET=$(echo -n "${ZFS_DATASET}" | awk 'BEGIN{FS=OFS="/"}{NF--; print}')
if [[ "${ZFS_DATASET}" == '' ]]; then
rootok=0
break
fi
else
rootok=1
break
fi
done
[[ "${rootok}" -eq 0 ]]&& return 1
ENCRYPTIONROOT=$(zfs get -H -o value encryptionroot ${ZFS_DATASET})
if ! [ "${ENCRYPTIONROOT}" = "-" ]; then
# decrypt them
TRY_COUNT=5
while [ $TRY_COUNT != 0 ]; do
zfs load-key "${ZFS_DATASET}"
[ $? == 0 ] && break
((TRY_COUNT-=1))
done
ask_for_password \
--tries 5 \
--prompt "Encrypted ZFS password for ${ENCRYPTIONROOT}: " \
--cmd "zfs load-key ${ENCRYPTIONROOT}"
fi
fi
# Let us tell the initrd to run on shutdown.

View File

@ -103,3 +103,75 @@ export_all() {
return ${ret}
}
# ask_for_password
#
# Wraps around plymouth ask-for-password and adds fallback to tty password ask
# if plymouth is not present.
#
# --cmd command
# Command to execute. Required.
# --prompt prompt
# Password prompt. Note that function already adds ':' at the end.
# Recommended.
# --tries n
# How many times repeat command on its failure. Default is 3.
# --ply-[cmd|prompt|tries]
# Command/prompt/tries specific for plymouth password ask only.
# --tty-[cmd|prompt|tries]
# Command/prompt/tries specific for tty password ask only.
# --tty-echo-off
# Turn off input echo before tty command is executed and turn on after.
# It's useful when password is read from stdin.
ask_for_password() {
local cmd; local prompt; local tries=3
local ply_cmd; local ply_prompt; local ply_tries=3
local tty_cmd; local tty_prompt; local tty_tries=3
local ret
while [ $# -gt 0 ]; do
case "$1" in
--cmd) ply_cmd="$2"; tty_cmd="$2"; shift;;
--ply-cmd) ply_cmd="$2"; shift;;
--tty-cmd) tty_cmd="$2"; shift;;
--prompt) ply_prompt="$2"; tty_prompt="$2"; shift;;
--ply-prompt) ply_prompt="$2"; shift;;
--tty-prompt) tty_prompt="$2"; shift;;
--tries) ply_tries="$2"; tty_tries="$2"; shift;;
--ply-tries) ply_tries="$2"; shift;;
--tty-tries) tty_tries="$2"; shift;;
--tty-echo-off) tty_echo_off=yes;;
esac
shift
done
{ flock -s 9;
# Prompt for password with plymouth, if installed and running.
if type plymouth >/dev/null 2>&1 && plymouth --ping 2>/dev/null; then
plymouth ask-for-password \
--prompt "$ply_prompt" --number-of-tries=$ply_tries \
--command="$ply_cmd"
ret=$?
else
if [ "$tty_echo_off" = yes ]; then
stty_orig="$(stty -g)"
stty -echo
fi
local i=1
while [ $i -le $tty_tries ]; do
[ -n "$tty_prompt" ] && \
printf "$tty_prompt [$i/$tty_tries]:" >&2
eval "$tty_cmd" && ret=0 && break
ret=$?
i=$(($i+1))
[ -n "$tty_prompt" ] && printf '\n' >&2
done
[ "$tty_echo_off" = yes ] && stty $stty_orig
fi
} 9>/.console_lock
[ $ret -ne 0 ] && echo "Wrong password" >&2
return $ret
}

View File

@ -33,21 +33,13 @@ fi
# if pool encryption is active and the zfs command understands '-o encryption'
if [[ $(zpool list -H -o feature@encryption $(echo "${root}" | awk -F\/ '{print $1}')) == 'active' ]]; then
# check if root dataset has encryption enabled
if $(zfs list -H -o encryption "${root}" | grep -q -v off); then
# figure out where the root dataset has its key, the keylocation should not be none
while true; do
if [[ $(zfs list -H -o keylocation "${root}") == 'none' ]]; then
root=$(echo -n "${root}" | awk 'BEGIN{FS=OFS="/"}{NF--; print}')
[[ "${root}" == '' ]] && exit 1
else
break
fi
done
# if the root dataset has encryption enabled
ENCRYPTIONROOT=$(zfs get -H -o value encryptionroot ${ZFS_DATASET})
if ! [ "${ENCRYPTIONROOT}" = "-" ]; then
# decrypt them
TRY_COUNT=5
while [ $TRY_COUNT != 0 ]; do
zfs load-key "$root" <<< $(systemd-ask-password "Encrypted ZFS password for ${root}: ")
zfs load-key "${ENCRYPTIONROOT}" <<< $(systemd-ask-password "Encrypted ZFS password for ${root}: ")
[[ $? == 0 ]] && break
((TRY_COUNT-=1))
done