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