]> granicus.if.org Git - zfs/commitdiff
Enable booting from nested encrypted datasets
authorKash Pande <kash@tripleback.net>
Tue, 20 Feb 2018 18:13:20 +0000 (13:13 -0500)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Fri, 23 Feb 2018 20:57:28 +0000 (12:57 -0800)
- 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

contrib/dracut/90zfs/mount-zfs.sh.in
contrib/dracut/90zfs/zfs-lib.sh.in
contrib/dracut/90zfs/zfs-load-key.sh.in

index 36f07d667be2caa3d2d3cf76793877de297f2ceb..5b6998b74a91977cf4c07897bc86e88caa260435 100755 (executable)
@@ -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.
index c988dfe606a53c2c7acaa70c83e0d38f6827b0d4..82666afd058fdf8a272711adeab1a31285baa7eb 100755 (executable)
@@ -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
+}
index 9a6241bd763477c24089776d1e2815331a2b18b1..6c1f423aea02c39c11c29dc17f2e740e3c6ff0c6 100755 (executable)
@@ -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