[PATCH] 90crypt: keys on external devices support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



99base/dracut-lib.sh: new fun.: getoptcomma, foreach_uuid_until
---
 modules.d/90crypt/cryptroot-ask.sh |  121 ++++++++++++++++++++++++++++--------
 modules.d/90crypt/parse-crypt.sh   |   45 +++++++++----
 modules.d/99base/dracut-lib.sh     |   57 +++++++++++++++++
 3 files changed, 182 insertions(+), 41 deletions(-)

diff --git a/modules.d/90crypt/cryptroot-ask.sh b/modules.d/90crypt/cryptroot-ask.sh
index a6a9af1..58bf667 100755
--- a/modules.d/90crypt/cryptroot-ask.sh
+++ b/modules.d/90crypt/cryptroot-ask.sh
@@ -26,40 +26,107 @@ fi
 
 if [ -f /etc/crypttab ] && ! getargs rd_NO_CRYPTTAB; then
     while read name dev rest; do
-	# ignore blank lines and comments
-	if [ -z "$name" -o "${name#\#}" != "$name" ]; then
-	    continue
-	fi
-
-	# UUID used in crypttab
-	if [ "${dev%%=*}" = "UUID" ]; then
-	    if [ "luks-${dev##UUID=}" = "$2" ]; then
-		luksname="$name"
-		break
-	    fi
-	
-	# path used in crypttab
-	else
-	    cdev=$(readlink -f $dev)
-	    mdev=$(readlink -f $device)
-	    if [ "$cdev" = "$mdev" ]; then
-		luksname="$name"
-		break
-	    fi
-	fi
+        # ignore blank lines and comments
+        if [ -z "$name" -o "${name#\#}" != "$name" ]; then
+            continue
+        fi
+
+        # UUID used in crypttab
+        if [ "${dev%%=*}" = "UUID" ]; then
+            if [ "luks-${dev##UUID=}" = "$2" ]; then
+                luksname="$name"
+                break
+            fi
+        
+        # path used in crypttab
+        else
+            cdev=$(readlink -f $dev)
+            mdev=$(readlink -f $device)
+            if [ "$cdev" = "$mdev" ]; then
+                luksname="$name"
+                break
+            fi
+        fi
     done < /etc/crypttab
     unset name dev rest
 fi
 
+#
+# Search key on external devices
+#
+
+# Try to mount device specified by UUID and probe for existence of any of
+# the paths.  On success return 0 and print "<uuid> <first-existing-path>",
+# otherwise return 1.
+# Function leaves mount point created.
+probe_keydev() {
+    local uuid="$1"; shift; local keypaths="$*"
+    local ret=1; local mount_point=/mnt/keydev
+    local path
+
+    [ -n "${uuid}" -a -n "${keypaths}" ] || return 1
+    [ -d ${mount_point} ] || mkdir -p "${mount_point}" || return 1
+
+    if mount -r -U "${uuid}" "${mount_point}" 2>/dev/null >/dev/null; then
+        for path in ${keypaths}; do
+            if [ -f "${mount_point}/${path}" ]; then
+                echo "${uuid} ${path}"
+                ret=0
+                break
+            fi
+        done
+    fi
+
+    umount "${mount_point}" 2>/dev/null >/dev/null
+
+    return ${ret}
+}
+
+keypaths="$(getargs rd_LUKS_KEYPATH)"
+unset keydev_uuid keypath
+
+if [ -n "$keypaths" ]; then
+    keydev_uuids="$(getargs rd_LUKS_KEYDEV_UUID)"
+    [ -n "$keydev_uuids" ] || {
+            warn 'No UUID of device storing LUKS key specified.'
+            warn 'It is recommended to set rd_LUKS_KEYDEV_UUID.'
+            warn 'Performing scan of *all* devices accessible by UUID...'
+    }
+    tmp=$(foreach_uuid_until "probe_keydev \$full_uuid $keypaths" \
+            $keydev_uuids) && {
+        keydev_uuid="${tmp%% *}"
+        keypath="${tmp#* }"
+    } || {
+        warn "Key for $device not found."
+    }
+    unset tmp keydev_uuids
+fi
+
+unset keypaths
+
+#
+# Open LUKS device
+#
+
 info "luksOpen $device $luksname"
-# flock against other interactive activities
-{ flock -s 9; 
-    echo -n "$device ($luksname) is password protected"
-    cryptsetup luksOpen -T1 $1 $luksname 
-} 9>/.console.lock
+
+if [ -n "$keydev_uuid" ]; then
+    mntp=/mnt/keydev
+    mkdir -p "$mntp"
+    mount -r -U "$keydev_uuid" "$mntp"
+    cryptsetup -d "$mntp/$keypath" luksOpen "$device" "$luksname"
+    umount "$mntp"
+    rmdir -p "$mntp" 2>/dev/null
+else
+    # flock against other interactive activities
+    { flock -s 9;
+        echo -n "$device ($luksname) is password protected"
+        cryptsetup luksOpen -T1 $1 $luksname
+    } 9>/.console.lock
+fi
 
 # mark device as asked
 >> /tmp/cryptroot-asked-$2
 
 exit 0
-# vim:ts=8:sw=4:sts=4:et
\ No newline at end of file
+# vim:ts=8:sw=4:sts=4:et
diff --git a/modules.d/90crypt/parse-crypt.sh b/modules.d/90crypt/parse-crypt.sh
index 04d9ecb..fce952d 100755
--- a/modules.d/90crypt/parse-crypt.sh
+++ b/modules.d/90crypt/parse-crypt.sh
@@ -4,23 +4,40 @@ if getarg rd_NO_LUKS; then
     rm -f /etc/udev/rules.d/70-luks.rules
 else
     {
-	echo 'SUBSYSTEM!="block", GOTO="luks_end"'
-	echo 'ACTION!="add|change", GOTO="luks_end"'
+        echo 'SUBSYSTEM!="block", GOTO="luks_end"'
+        echo 'ACTION!="add|change", GOTO="luks_end"'
     } > /etc/udev/rules.d/70-luks.rules
-    LUKS=$(getargs rd_LUKS_UUID=)
+
+    LUKS=$(getargs rd_LUKS_UUID)
+    unset settled
+    [ -n "$(getargs rd_LUKS_KEYPATH)" ] && \
+            [ -z "$(getargs rd_LUKS_KEYDEV_UUID)" ] && \
+            settled='--settled'
+
     if [ -n "$LUKS" ]; then
-	echo '. /lib/dracut-lib.sh' > /emergency/crypt.sh
-	for luksid in $LUKS; do 
-	printf 'ENV{ID_FS_TYPE}=="crypto_LUKS", ENV{ID_FS_UUID}=="*%s*", RUN+="/sbin/initqueue --unique --onetime --name cryptroot-ask-%%k /sbin/cryptroot-ask $env{DEVNAME} luks-$env{ID_FS_UUID}"\n' $luksid \
-	    >> /etc/udev/rules.d/70-luks.rules	
-	printf '[ -e /dev/disk/by-uuid/*%s* ] || exit 1 \n'  $luksid >> /initqueue-finished/crypt.sh
-	printf '[ -e /dev/disk/by-uuid/*%s* ] || warn "crypto LUKS UUID "%s" not found" \n' $luksid $luksid >> /emergency/00-crypt.sh
-	done
+        echo '. /lib/dracut-lib.sh' > /emergency/crypt.sh
+        for luksid in $LUKS; do 
+            {
+                printf 'ENV{ID_FS_TYPE}=="crypto_LUKS", '
+                printf 'ENV{ID_FS_UUID}=="*%s*", ' $luksid
+                printf 'RUN+="/sbin/initqueue --unique --onetime %s ' "$settled"
+                printf '--name cryptroot-ask-%%k /sbin/cryptroot-ask '
+                printf '$env{DEVNAME} luks-$env{ID_FS_UUID}"\n'
+            } >> /etc/udev/rules.d/70-luks.rules
+
+            printf '[ -e /dev/disk/by-uuid/*%s* ] || exit 1\n' $luksid \
+                    >> /initqueue-finished/crypt.sh
+            {
+                printf '[ -e /dev/disk/by-uuid/*%s* ] || ' $luksid
+                printf 'warn "crypto LUKS UUID "%s" not found"\n' $luksid
+            } >> /emergency/00-crypt.sh
+        done
     else
-	echo 'ENV{ID_FS_TYPE}=="crypto_LUKS", RUN+="/sbin/initqueue --unique --onetime --name cryptroot-ask-%k /sbin/cryptroot-ask $env{DEVNAME} luks-$env{ID_FS_UUID}"' \
-	    >> /etc/udev/rules.d/70-luks.rules	
+        echo 'ENV{ID_FS_TYPE}=="crypto_LUKS", RUN+="/sbin/initqueue' $settled \
+                '--unique --onetime --name cryptroot-ask-%k' \
+                '/sbin/cryptroot-ask $env{DEVNAME} luks-$env{ID_FS_UUID}"' \
+                >> /etc/udev/rules.d/70-luks.rules
     fi
-    echo 'LABEL="luks_end"' >> /etc/udev/rules.d/70-luks.rules
 
+    echo 'LABEL="luks_end"' >> /etc/udev/rules.d/70-luks.rules
 fi
-
diff --git a/modules.d/99base/dracut-lib.sh b/modules.d/99base/dracut-lib.sh
index 2624f7d..84bb5fa 100755
--- a/modules.d/99base/dracut-lib.sh
+++ b/modules.d/99base/dracut-lib.sh
@@ -48,6 +48,31 @@ getargs() {
     return 1;
 }
 
+# Prints value of given option.  If option is a flag and it's present,
+# it just returns 0.  Otherwise 1 is returned.
+# $1 = options separated by commas
+# $2 = option we are interested in
+# 
+# Example:
+# $1 = cipher=aes-cbc-essiv:sha256,hash=sha256,verify
+# $2 = hash
+# Output:
+# sha256
+getoptcomma() {
+    local line=",$1,"; local opt="$2"; local tmp
+
+    case "${line}" in
+        *,${opt}=*,*)
+            tmp="${line#*,${opt}=}"
+            echo "${tmp%%,*}"
+            return 0
+        ;;
+        *,${opt},*) return 0 ;;
+    esac
+
+    return 1
+}
+
 setdebug() {
     if [ -z "$RDDEBUG" ]; then
         if [ -e /proc/cmdline ]; then
@@ -243,3 +268,35 @@ ip_to_var() {
     esac
 }
 
+# Evaluate command for UUIDs either given as arguments for this function or all
+# listed in /dev/disk/by-uuid.  UUIDs doesn't have to be fully specified.  If
+# beginning is given it is expanded to all matching UUIDs.  To pass full UUID
+# to your command use '${full_uuid}'.  Remember to escape '$'!
+#
+# $1 = command to be evaluated
+# $2 = list of UUIDs separated by space
+#
+# The function returns after *first successful evaluation* of the given command
+# with status 0.  If evaluation fails for every UUID function returns with
+# status 1.
+#
+# Example:
+# foreach_uuid_until "mount -U \${full_uuid} /mnt; echo OK; umount /mnt" \
+#       "01234 f512 a235567f-12a3-c123-a1b1-01234567abcb"
+foreach_uuid_until() (
+    cd /dev/disk/by-uuid
+
+    local cmd="$1"; shift; local uuids_list="$*"
+    local uuid; local full_uuid
+
+    [ -n "${cmd}" ] || return 1
+
+    for uuid in ${uuids_list:-*}; do
+        for full_uuid in ${uuid}*; do
+            [ -e "${full_uuid}" ] || continue
+            eval ${cmd} && return 0
+        done
+    done
+
+    return 1
+)
-- 
1.7.1

Attachment: signature.asc
Description: PGP signature


[Index of Archives]     [Linux Kernel]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux SCSI]

  Powered by Linux