Re: [PATCH] 90crypt: keys on external devices support

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

 



pushed
On 07/13/2010 07:14 PM, Amadeusz Żołnowski wrote:
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
+)

--
To unsubscribe from this list: send the line "unsubscribe initramfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

  Powered by Linux