if [ -f /etc/crypttab ] && ! getarg 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
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
-
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
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
+)