summaryrefslogtreecommitdiffstats
path: root/modules.d/90crypt
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-03 13:54:25 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-03 13:54:25 +0000
commit9cb1c4df7b9ce1a9ad1312621b0f2b16a94fba3a (patch)
tree2efb72864cc69e174c9c5ee33efb88a5f1553b48 /modules.d/90crypt
parentInitial commit. (diff)
downloaddracut-9cb1c4df7b9ce1a9ad1312621b0f2b16a94fba3a.tar.xz
dracut-9cb1c4df7b9ce1a9ad1312621b0f2b16a94fba3a.zip
Adding upstream version 060+5.upstream/060+5
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'modules.d/90crypt')
-rwxr-xr-xmodules.d/90crypt/crypt-cleanup.sh14
-rwxr-xr-xmodules.d/90crypt/crypt-lib.sh278
-rwxr-xr-xmodules.d/90crypt/crypt-run-generator.sh31
-rwxr-xr-xmodules.d/90crypt/cryptroot-ask.sh207
-rwxr-xr-xmodules.d/90crypt/module-setup.sh186
-rwxr-xr-xmodules.d/90crypt/parse-crypt.sh197
-rwxr-xr-xmodules.d/90crypt/parse-keydev.sh44
-rwxr-xr-xmodules.d/90crypt/probe-keydev.sh16
8 files changed, 973 insertions, 0 deletions
diff --git a/modules.d/90crypt/crypt-cleanup.sh b/modules.d/90crypt/crypt-cleanup.sh
new file mode 100755
index 0000000..94fa724
--- /dev/null
+++ b/modules.d/90crypt/crypt-cleanup.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+# close everything which is not busy
+rm -f -- /etc/udev/rules.d/70-luks.rules > /dev/null 2>&1
+
+if ! getarg rd.luks.uuid -d rd_LUKS_UUID > /dev/null 2>&1 && getargbool 1 rd.luks -d -n rd_NO_LUKS > /dev/null 2>&1; then
+ while true; do
+ local do_break="y"
+ for i in /dev/mapper/luks-*; do
+ cryptsetup luksClose "$i" > /dev/null 2>&1 && do_break=n
+ done
+ [ "$do_break" = "y" ] && break
+ done
+fi
diff --git a/modules.d/90crypt/crypt-lib.sh b/modules.d/90crypt/crypt-lib.sh
new file mode 100755
index 0000000..f3ba20d
--- /dev/null
+++ b/modules.d/90crypt/crypt-lib.sh
@@ -0,0 +1,278 @@
+#!/bin/sh
+
+command -v getarg > /dev/null || . /lib/dracut-lib.sh
+
+# check if the crypttab contains an entry for a LUKS UUID
+crypttab_contains() {
+ local luks="$1"
+ local dev="$2"
+ local l d rest
+ if [ -f /etc/crypttab ]; then
+ while read -r l d rest || [ -n "$l" ]; do
+ strstr "${l##luks-}" "${luks##luks-}" && return 0
+ strstr "$d" "${luks##luks-}" && return 0
+ if [ -n "$dev" ]; then
+ for _dev in $(devnames "$d"); do
+ [ "$dev" -ef "$_dev" ] && return 0
+ done
+ fi
+ if [ -e /etc/block_uuid.map ]; then
+ # search for line starting with $d
+ _line=$(sed -n "\,^$d .*$,{p}" /etc/block_uuid.map)
+ [ -z "$_line" ] && continue
+ # get second column with uuid
+ _uuid="$(echo "$_line" | sed 's,^.* \(.*$\),\1,')"
+ strstr "$_uuid" "${luks##luks-}" && return 0
+ fi
+ done < /etc/crypttab
+ fi
+ return 1
+}
+
+# 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 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 "%s" "$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
+}
+
+# Try to mount specified device (by path, by UUID or by label) and check
+# the path with 'test'.
+#
+# example:
+# test_dev -f LABEL="nice label" /some/file1
+test_dev() {
+ local test_op="$1"
+ local dev="$2"
+ local f="$3"
+ local ret=1
+ local mount_point
+
+ mount_point=$(mkuniqdir /mnt testdev)
+ [ -n "$dev" -a -n "$*" ] || return 1
+ [ -d "$mount_point" ] || die 'Mount point does not exist!'
+
+ if mount -r "$dev" "$mount_point" > /dev/null 2>&1; then
+ test "$test_op" "${mount_point}/${f}"
+ ret=$?
+ umount "$mount_point"
+ fi
+
+ rmdir "$mount_point"
+
+ return $ret
+}
+
+# match_dev devpattern dev
+#
+# Returns true if 'dev' matches 'devpattern'. Both 'devpattern' and 'dev' are
+# expanded to kernel names and then compared. If name of 'dev' is on list of
+# names of devices matching 'devpattern', the test is positive. 'dev' and
+# 'devpattern' may be anything which function 'devnames' recognizes.
+#
+# If 'devpattern' is empty or '*' then function just returns true.
+#
+# Example:
+# match_dev UUID=123 /dev/dm-1
+# Returns true if /dev/dm-1 UUID starts with "123".
+match_dev() {
+ [ -z "$1" -o "$1" = '*' ] && return 0
+ local devlist
+ local dev
+
+ devlist="$(devnames "$1")" || return 255
+ dev="$(devnames "$2")" || return 255
+
+ strstr "
+$devlist
+" "
+$dev
+"
+}
+
+# getkey keysfile for_dev
+#
+# Reads file <keysfile> produced by probe-keydev and looks for first line to
+# which device <for_dev> matches. The successful result is printed in format
+# "<keydev>:<keypath>". When nothing found, just false is returned.
+#
+# Example:
+# getkey /tmp/luks.keys /dev/sdb1
+# May print:
+# /dev/sdc1:/keys/some.key
+getkey() {
+ local keys_file="$1"
+ local for_dev="$2"
+ local luks_dev
+ local key_dev
+ local key_path
+
+ [ -z "$keys_file" -o -z "$for_dev" ] && die 'getkey: wrong usage!'
+ [ -f "$keys_file" ] || return 1
+
+ while IFS=: read -r luks_dev key_dev key_path _ || [ -n "$luks_dev" ]; do
+ if match_dev "$luks_dev" "$for_dev"; then
+ echo "${key_dev}:${key_path}"
+ return 0
+ fi
+ done < "$keys_file"
+
+ return 1
+}
+
+# readkey keypath keydev device
+#
+# Mounts <keydev>, reads key from file <keypath>, optionally processes it (e.g.
+# if encrypted with GPG) and prints to standard output which is supposed to be
+# read by cryptsetup. <device> is just passed to helper function for
+# informational purpose.
+readkey() {
+ local keypath="$1"
+ local keydev="$2"
+ local device="$3"
+
+ # No mounting needed if the keyfile resides inside the initrd
+ if [ "/" = "$keydev" ]; then
+ local mntp=/
+ else
+ # This creates a unique single mountpoint for *, or several for explicitly
+ # given LUKS devices. It accomplishes unlocking multiple LUKS devices with
+ # a single password entry.
+ local mntp
+ mntp="/mnt/$(str_replace "keydev-$keydev-$keypath" '/' '-')"
+
+ if [ ! -d "$mntp" ]; then
+ mkdir -p "$mntp"
+ mount -r "$keydev" "$mntp" || die 'Mounting rem. dev. failed!'
+ fi
+ fi
+
+ case "${keypath##*.}" in
+ gpg)
+ if [ -f /lib/dracut-crypt-gpg-lib.sh ]; then
+ . /lib/dracut-crypt-gpg-lib.sh
+ gpg_decrypt "$mntp" "$keypath" "$keydev" "$device"
+ else
+ die "No GPG support to decrypt '$keypath' on '$keydev'."
+ fi
+ ;;
+ img)
+ if [ -f /lib/dracut-crypt-loop-lib.sh ]; then
+ . /lib/dracut-crypt-loop-lib.sh
+ loop_decrypt "$mntp" "$keypath" "$keydev" "$device"
+ printf "%s\n" "umount \"$mntp\"; rmdir \"$mntp\";" > "${hookdir}/cleanup/crypt-loop-cleanup-99-${mntp##*/}".sh
+ return 0
+ else
+ die "No loop file support to decrypt '$keypath' on '$keydev'."
+ fi
+ ;;
+ *) cat "$mntp/$keypath" ;;
+ esac
+
+ # No unmounting if the keyfile resides inside the initrd
+ if [ "/" != "$keydev" ]; then
+ # General unmounting mechanism, modules doing custom cleanup should return earlier
+ # and install a pre-pivot cleanup hook
+ umount "$mntp"
+ rmdir "$mntp"
+ fi
+}
diff --git a/modules.d/90crypt/crypt-run-generator.sh b/modules.d/90crypt/crypt-run-generator.sh
new file mode 100755
index 0000000..3e78e6d
--- /dev/null
+++ b/modules.d/90crypt/crypt-run-generator.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+. /lib/dracut-lib.sh
+type crypttab_contains > /dev/null 2>&1 || . /lib/dracut-crypt-lib.sh
+
+dev=$1
+luks=$2
+
+crypttab_contains "$luks" "$dev" && exit 0
+
+allowdiscards="-"
+
+# parse for allow-discards
+if [ -n "$DRACUT_SYSTEMD" ] || strstr "$(cryptsetup --help)" "allow-discards"; then
+ if discarduuids=$(getargs "rd.luks.allow-discards"); then
+ discarduuids=$(str_replace "$discarduuids" 'luks-' '')
+ if strstr " $discarduuids " " ${luks##luks-}"; then
+ allowdiscards="discard"
+ fi
+ elif getargbool 0 rd.luks.allow-discards; then
+ allowdiscards="discard"
+ fi
+fi
+
+echo "$luks $dev - timeout=0,$allowdiscards" >> /etc/crypttab
+
+if command -v systemctl > /dev/null; then
+ systemctl daemon-reload
+ systemctl start cryptsetup.target
+fi
+exit 0
diff --git a/modules.d/90crypt/cryptroot-ask.sh b/modules.d/90crypt/cryptroot-ask.sh
new file mode 100755
index 0000000..b1f8df8
--- /dev/null
+++ b/modules.d/90crypt/cryptroot-ask.sh
@@ -0,0 +1,207 @@
+#!/bin/sh
+
+PATH=/usr/sbin:/usr/bin:/sbin:/bin
+NEWROOT=${NEWROOT:-"/sysroot"}
+
+# do not ask, if we already have root
+[ -f "$NEWROOT"/proc ] && exit 0
+
+. /lib/dracut-lib.sh
+
+mkdir -p -m 0700 /run/cryptsetup
+
+# if device name is /dev/dm-X, convert to /dev/mapper/name
+if [ "${1##/dev/dm-}" != "$1" ]; then
+ device="/dev/mapper/$(dmsetup info -c --noheadings -o name "$1")"
+else
+ device="$1"
+fi
+
+# default luksname - luks-UUID
+luksname=$2
+
+# is_keysource - ask for passphrase even if a rd.luks.key argument is set
+is_keysource=${3:-0}
+
+# number of tries
+numtries=${4:-10}
+
+# TODO: improve to support what cmdline does
+if [ -f /etc/crypttab ] && getargbool 1 rd.luks.crypttab -d -n rd_NO_CRYPTTAB; then
+ while read -r name dev luksfile luksoptions || [ -n "$name" ]; do
+ # ignore blank lines and comments
+ if [ -z "$name" -o "${name#\#}" != "$name" ]; then
+ continue
+ fi
+
+ # PARTUUID used in crypttab
+ if [ "${dev%%=*}" = "PARTUUID" ]; then
+ if [ "luks-${dev##PARTUUID=}" = "$luksname" ]; then
+ luksname="$name"
+ break
+ fi
+
+ # UUID used in crypttab
+ elif [ "${dev%%=*}" = "UUID" ]; then
+ if [ "luks-${dev##UUID=}" = "$luksname" ]; then
+ luksname="$name"
+ break
+ fi
+
+ # ID used in crypttab
+ elif [ "${dev%%=*}" = "ID" ]; then
+ if [ "luks-${dev##ID=}" = "$luksname" ]; 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
+fi
+
+# check if destination already exists
+[ -b /dev/mapper/"$luksname" ] && exit 0
+
+# we already asked for this device
+asked_file=/tmp/cryptroot-asked-$luksname
+[ -f "$asked_file" ] && exit 0
+
+# load dm_crypt if it is not already loaded
+[ -d /sys/module/dm_crypt ] || modprobe dm_crypt
+
+. /lib/dracut-crypt-lib.sh
+
+#
+# Open LUKS device
+#
+
+info "luksOpen $device $luksname $luksfile $luksoptions"
+
+OLD_IFS="$IFS"
+IFS=,
+# shellcheck disable=SC2086
+set -- $luksoptions
+IFS="$OLD_IFS"
+
+while [ $# -gt 0 ]; do
+ case $1 in
+ noauto)
+ # skip this
+ exit 0
+ ;;
+ swap)
+ # skip this
+ exit 0
+ ;;
+ tmp)
+ # skip this
+ exit 0
+ ;;
+ allow-discards)
+ allowdiscards="--allow-discards"
+ ;;
+ header=*)
+ cryptsetupopts="${cryptsetupopts} --${1}"
+ ;;
+ esac
+ shift
+done
+
+# parse for allow-discards
+if strstr "$(cryptsetup --help)" "allow-discards"; then
+ if discarduuids=$(getargs "rd.luks.allow-discards"); then
+ discarduuids=$(str_replace "$discarduuids" 'luks-' '')
+ if strstr " $discarduuids " " ${luksdev##luks-}"; then
+ allowdiscards="--allow-discards"
+ fi
+ elif getargbool 0 rd.luks.allow-discards; then
+ allowdiscards="--allow-discards"
+ fi
+fi
+
+if strstr "$(cryptsetup --help)" "allow-discards"; then
+ cryptsetupopts="$cryptsetupopts $allowdiscards"
+fi
+
+unset allowdiscards
+
+# fallback to passphrase
+ask_passphrase=1
+
+if [ -n "$luksfile" -a "$luksfile" != "none" -a -e "$luksfile" ]; then
+ # shellcheck disable=SC2086
+ if readkey "$luksfile" / "$device" \
+ | cryptsetup -d - $cryptsetupopts luksOpen "$device" "$luksname"; then
+ ask_passphrase=0
+ fi
+elif [ "$is_keysource" -ne 0 ]; then
+ info "Asking for passphrase because $device is a keysource."
+else
+ while [ -n "$(getarg rd.luks.key)" ]; do
+ if tmp=$(getkey /tmp/luks.keys "$device"); then
+ keydev="${tmp%%:*}"
+ keypath="${tmp#*:}"
+ else
+ if [ "$numtries" -eq 0 ]; then
+ warn "No key found for $device. Fallback to passphrase mode."
+ break
+ fi
+ sleep 1
+ info "No key found for $device. Will try $numtries time(s) more later."
+ initqueue --unique --onetime --settled \
+ --name cryptroot-ask-"$luksname" \
+ "$(command -v cryptroot-ask)" "$device" "$luksname" "$is_keysource" "$((numtries - 1))"
+ exit 0
+ fi
+ unset tmp
+
+ info "Using '$keypath' on '$keydev'"
+ # shellcheck disable=SC2086
+ readkey "$keypath" "$keydev" "$device" \
+ | cryptsetup -d - $cryptsetupopts luksOpen "$device" "$luksname" \
+ && ask_passphrase=0
+ unset keypath keydev
+ break
+ done
+fi
+
+if [ $ask_passphrase -ne 0 ]; then
+ luks_open="$(command -v cryptsetup) $cryptsetupopts luksOpen"
+ _timeout=$(getargs "rd.luks.timeout")
+ _timeout=${_timeout:-0}
+ ask_for_password --ply-tries 5 \
+ --ply-cmd "$luks_open -T1 $device $luksname" \
+ --ply-prompt "Password ($device)" \
+ --tty-tries 1 \
+ --tty-cmd "$luks_open -T5 -t $_timeout $device $luksname"
+ unset luks_open
+ unset _timeout
+fi
+
+if [ "$is_keysource" -ne 0 -a "${luksname##luks-}" != "$luksname" ]; then
+ luks_close="$(command -v cryptsetup) close"
+ {
+ printf -- '[ -e /dev/mapper/%s ] && ' "$luksname"
+ printf -- '%s "%s"\n' "$luks_close" "$luksname"
+ } >> "$hookdir/cleanup/31-crypt-keysource.sh"
+ unset luks_close
+fi
+
+unset device luksname luksfile
+
+# mark device as asked
+: >> "$asked_file"
+
+need_shutdown
+udevsettle
+
+exit 0
diff --git a/modules.d/90crypt/module-setup.sh b/modules.d/90crypt/module-setup.sh
new file mode 100755
index 0000000..d5ac45b
--- /dev/null
+++ b/modules.d/90crypt/module-setup.sh
@@ -0,0 +1,186 @@
+#!/bin/bash
+
+# called by dracut
+check() {
+ local fs
+ # if cryptsetup is not installed, then we cannot support encrypted devices.
+ require_any_binary "$systemdutildir"/systemd-cryptsetup cryptsetup || return 1
+
+ [[ $hostonly ]] || [[ $mount_needs ]] && {
+ for fs in "${host_fs_types[@]}"; do
+ [[ $fs == "crypto_LUKS" ]] && return 0
+ done
+ return 255
+ }
+
+ return 0
+}
+
+# called by dracut
+depends() {
+ local deps
+ deps="dm rootfs-block"
+ if [[ $hostonly && -f "$dracutsysrootdir"/etc/crypttab ]]; then
+ if grep -q -e "fido2-device=" -e "fido2-cid=" "$dracutsysrootdir"/etc/crypttab; then
+ deps+=" fido2"
+ fi
+ if grep -q "pkcs11-uri" "$dracutsysrootdir"/etc/crypttab; then
+ deps+=" pkcs11"
+ fi
+ if grep -q "tpm2-device=" "$dracutsysrootdir"/etc/crypttab; then
+ deps+=" tpm2-tss"
+ fi
+ fi
+ echo "$deps"
+ return 0
+}
+
+# called by dracut
+installkernel() {
+ hostonly="" instmods drbg
+ instmods dm_crypt
+
+ # in case some of the crypto modules moved from compiled in
+ # to module based, try to install those modules
+ # best guess
+ if [[ $hostonly ]] || [[ $mount_needs ]]; then
+ # dmsetup returns s.th. like
+ # cryptvol: 0 2064384 crypt aes-xts-plain64 :64:logon:cryptsetup:....
+ dmsetup table | while read -r name _ _ is_crypt cipher _; do
+ [[ $is_crypt == "crypt" ]] || continue
+ # get the device name
+ name=/dev/$(dmsetup info -c --noheadings -o blkdevname "${name%:}")
+ # check if the device exists as a key in our host_fs_types (even with null string)
+ # shellcheck disable=SC2030 # this is a shellcheck bug
+ if [[ ${host_fs_types[$name]+_} ]]; then
+ # split the cipher aes-xts-plain64 in pieces
+ IFS='-:' read -ra mods <<< "$cipher"
+ # try to load the cipher part with "crypto-" prepended
+ # in non-hostonly mode
+ hostonly='' instmods "${mods[@]/#/crypto-}" "crypto-$cipher"
+ fi
+ done
+ else
+ instmods "=crypto"
+ fi
+ return 0
+}
+
+# called by dracut
+cmdline() {
+ local dev UUID
+ # shellcheck disable=SC2031
+ for dev in "${!host_fs_types[@]}"; do
+ [[ ${host_fs_types[$dev]} != "crypto_LUKS" ]] && continue
+
+ UUID=$(
+ blkid -u crypto -o export "$dev" \
+ | while read -r line || [ -n "$line" ]; do
+ [[ ${line#UUID} == "$line" ]] && continue
+ printf "%s" "${line#UUID=}"
+ break
+ done
+ )
+ [[ ${UUID} ]] || continue
+ printf "%s" " rd.luks.uuid=luks-${UUID}"
+ done
+}
+
+# called by dracut
+install() {
+
+ if [[ $hostonly_cmdline == "yes" ]]; then
+ local _cryptconf
+ _cryptconf=$(cmdline)
+ [[ $_cryptconf ]] && printf "%s\n" "$_cryptconf" >> "${initdir}/etc/cmdline.d/90crypt.conf"
+ fi
+
+ inst_hook cmdline 30 "$moddir/parse-crypt.sh"
+ if ! dracut_module_included "systemd"; then
+ inst_multiple cryptsetup rmdir readlink umount
+ inst_script "$moddir"/cryptroot-ask.sh /sbin/cryptroot-ask
+ inst_script "$moddir"/probe-keydev.sh /sbin/probe-keydev
+ inst_hook cmdline 10 "$moddir/parse-keydev.sh"
+ inst_hook cleanup 30 "$moddir/crypt-cleanup.sh"
+ fi
+
+ if [[ $hostonly ]] && [[ -f $dracutsysrootdir/etc/crypttab ]]; then
+ # filter /etc/crypttab for the devices we need
+ while read -r _mapper _dev _luksfile _luksoptions || [ -n "$_mapper" ]; do
+ [[ $_mapper == \#* ]] && continue
+ [[ $_dev ]] || continue
+
+ [[ $_dev == PARTUUID=* ]] \
+ && _dev="/dev/disk/by-partuuid/${_dev#PARTUUID=}"
+
+ [[ $_dev == UUID=* ]] \
+ && _dev="/dev/disk/by-uuid/${_dev#UUID=}"
+
+ [[ $_dev == ID=* ]] \
+ && _dev="/dev/disk/by-id/${_dev#ID=}"
+
+ echo "$_dev $(blkid "$_dev" -s UUID -o value)" >> "${initdir}/etc/block_uuid.map"
+
+ # loop through the options to check for the force option
+ luksoptions=${_luksoptions}
+ OLD_IFS="${IFS}"
+ IFS=,
+ # shellcheck disable=SC2086
+ set -- ${luksoptions}
+ IFS="${OLD_IFS}"
+
+ forceentry=""
+ while [ $# -gt 0 ]; do
+ case $1 in
+ force)
+ forceentry="yes"
+ break
+ ;;
+ esac
+ shift
+ done
+
+ # include the entry regardless
+ if [ "${forceentry}" = "yes" ]; then
+ echo "$_mapper $_dev $_luksfile $_luksoptions"
+ else
+ # shellcheck disable=SC2031
+ for _hdev in "${!host_fs_types[@]}"; do
+ [[ ${host_fs_types[$_hdev]} == "crypto_LUKS" ]] || continue
+ if [[ $_hdev -ef $_dev ]] || [[ /dev/block/$_hdev -ef $_dev ]]; then
+ echo "$_mapper $_dev $_luksfile $_luksoptions"
+ break
+ fi
+ done
+ fi
+ done < "$dracutsysrootdir"/etc/crypttab > "$initdir"/etc/crypttab
+ mark_hostonly /etc/crypttab
+ fi
+
+ inst_simple "$moddir/crypt-lib.sh" "/lib/dracut-crypt-lib.sh"
+ inst_script "$moddir/crypt-run-generator.sh" "/sbin/crypt-run-generator"
+
+ if dracut_module_included "systemd"; then
+ # the cryptsetup targets are already pulled in by 00systemd, but not
+ # the enablement symlinks
+ inst_multiple -o \
+ "$tmpfilesdir"/cryptsetup.conf \
+ "$systemdutildir"/system-generators/systemd-cryptsetup-generator \
+ "$systemdutildir"/systemd-cryptsetup \
+ "$systemdsystemunitdir"/systemd-ask-password-console.path \
+ "$systemdsystemunitdir"/systemd-ask-password-console.service \
+ "$systemdsystemunitdir"/cryptsetup.target \
+ "$systemdsystemunitdir"/sysinit.target.wants/cryptsetup.target \
+ "$systemdsystemunitdir"/remote-cryptsetup.target \
+ "$systemdsystemunitdir"/initrd-root-device.target.wants/remote-cryptsetup.target \
+ systemd-ask-password systemd-tty-ask-password-agent
+ fi
+
+ # Install required libraries.
+ _arch=${DRACUT_ARCH:-$(uname -m)}
+ inst_libdir_file \
+ {"tls/$_arch/",tls/,"$_arch/",}"/ossl-modules/fips.so" \
+ {"tls/$_arch/",tls/,"$_arch/",}"/ossl-modules/legacy.so"
+
+ dracut_need_initqueue
+}
diff --git a/modules.d/90crypt/parse-crypt.sh b/modules.d/90crypt/parse-crypt.sh
new file mode 100755
index 0000000..e46e347
--- /dev/null
+++ b/modules.d/90crypt/parse-crypt.sh
@@ -0,0 +1,197 @@
+#!/bin/sh
+
+type crypttab_contains > /dev/null 2>&1 || . /lib/dracut-crypt-lib.sh
+
+_cryptgetargsname() {
+ debug_off
+ local _o _found _key
+ unset _o
+ unset _found
+ _key="$1"
+ set --
+ for _o in $(getargs rd.luks.name); do
+ if [ "${_o%=*}" = "${_key%=}" ]; then
+ [ -n "${_o%=*}" ] && set -- "$@" "${_o#*=}"
+ _found=1
+ fi
+ done
+ if [ -n "$_found" ]; then
+ [ $# -gt 0 ] && printf '%s' "$*"
+ return 0
+ fi
+ return 1
+}
+
+if ! getargbool 1 rd.luks -d -n rd_NO_LUKS; then
+ info "rd.luks=0: removing cryptoluks activation"
+ rm -f -- /etc/udev/rules.d/70-luks.rules
+else
+ {
+ echo 'SUBSYSTEM!="block", GOTO="luks_end"'
+ echo 'ACTION!="add|change", GOTO="luks_end"'
+ } > /etc/udev/rules.d/70-luks.rules.new
+
+ PARTUUID=$(getargs rd.luks.partuuid -d rd_LUKS_PARTUUID)
+ SERIAL=$(getargs rd.luks.serial -d rd_LUKS_SERIAL)
+ LUKS=$(getargs rd.luks.uuid -d rd_LUKS_UUID)
+ tout=$(getarg rd.luks.key.tout)
+
+ if [ -e /etc/crypttab ]; then
+ while read -r _ _dev _ || [ -n "$_dev" ]; do
+ set_systemd_timeout_for_dev "$_dev"
+ done < /etc/crypttab
+ fi
+
+ if [ -n "$PARTUUID" ]; then
+ for uuid in $PARTUUID; do
+
+ is_keysource=0
+ _uuid=$uuid
+ uuid=${uuid#keysource:}
+ [ "$uuid" != "$_uuid" ] && is_keysource=1
+ unset _uuid
+
+ uuid=${uuid##luks-}
+ if luksname=$(_cryptgetargsname "$uuid="); then
+ luksname="${luksname#"$uuid"=}"
+ else
+ luksname="luks-$uuid"
+ fi
+
+ if [ -z "$DRACUT_SYSTEMD" ]; then
+ {
+ printf -- 'ENV{ID_PART_ENTRY_UUID}=="*%s*", ' "$uuid"
+ printf -- 'RUN+="%s --settled --unique --onetime ' "$(command -v initqueue)"
+ printf -- '--name cryptroot-ask-%%k %s ' "$(command -v cryptroot-ask)"
+ # shellcheck disable=SC2016
+ printf -- '$env{DEVNAME} %s %s %s"\n' "$luksname" "$is_keysource" "$tout"
+ } >> /etc/udev/rules.d/70-luks.rules.new
+ else
+ luksname=$(dev_unit_name "$luksname")
+ # shellcheck disable=SC1003
+ luksname="$(str_replace "$luksname" '\' '\\')"
+
+ if ! crypttab_contains "$uuid"; then
+ {
+ printf -- 'ENV{ID_PART_ENTRY_UUID}=="*%s*", ' "$uuid"
+ printf -- 'RUN+="%s --settled --unique --onetime ' "$(command -v initqueue)"
+ printf -- '--name systemd-cryptsetup-%%k %s start ' "$(command -v systemctl)"
+ printf -- 'systemd-cryptsetup@%s.service"\n' "$luksname"
+ } >> /etc/udev/rules.d/70-luks.rules.new
+ fi
+ fi
+ done
+
+ elif [ -n "$SERIAL" ]; then
+ for serialid in $SERIAL; do
+
+ is_keysource=0
+ _serialid=$serialid
+ serialid=${serialid#keysource:}
+ [ "$serialid" != "$_serialid" ] && is_keysource=1
+ unset _serialid
+
+ serialid=${serialid##luks-}
+ if luksname=$(_cryptgetargsname "$serialid="); then
+ luksname="${luksname#"$serialid"=}"
+ else
+ luksname="luks-$serialid"
+ fi
+
+ if [ -z "$DRACUT_SYSTEMD" ]; then
+ {
+ printf -- 'ENV{ID_SERIAL_SHORT}=="*%s*", ' "$serialid"
+ printf -- 'RUN+="%s --settled --unique --onetime ' "$(command -v initqueue)"
+ printf -- '--name cryptroot-ask-%%k %s ' "$(command -v cryptroot-ask)"
+ # shellcheck disable=SC2016
+ printf -- '$env{DEVNAME} %s %s %s"\n' "$luksname" "$is_keysource" "$tout"
+ } >> /etc/udev/rules.d/70-luks.rules.new
+ else
+ luksname=$(dev_unit_name "$luksname")
+ # shellcheck disable=SC1003
+ luksname="$(str_replace "$luksname" '\' '\\')"
+
+ if ! crypttab_contains "$serialid"; then
+ {
+ printf -- 'ENV{ID_SERIAL_SHORT}=="*%s*", ' "$serialid"
+ printf -- 'RUN+="%s --settled --unique --onetime ' "$(command -v initqueue)"
+ printf -- '--name systemd-cryptsetup-%%k %s start ' "$(command -v systemctl)"
+ printf -- 'systemd-cryptsetup@%s.service"\n' "$luksname"
+ } >> /etc/udev/rules.d/70-luks.rules.new
+ fi
+ fi
+ done
+
+ elif [ -n "$LUKS" ]; then
+ for luksid in $LUKS; do
+
+ is_keysource=0
+ _luksid=$luksid
+ luksid=${luksid#keysource:}
+ [ "$luksid" != "$_luksid" ] && is_keysource=1
+ unset _luksid
+
+ luksid=${luksid##luks-}
+ if luksname=$(_cryptgetargsname "$luksid="); then
+ luksname="${luksname#"$luksid"=}"
+ else
+ luksname="luks-$luksid"
+ fi
+
+ if [ -z "$DRACUT_SYSTEMD" ]; then
+ {
+ printf -- 'ENV{ID_FS_TYPE}=="crypto_LUKS", '
+ printf -- 'ENV{ID_FS_UUID}=="*%s*", ' "$luksid"
+ printf -- 'RUN+="%s --settled --unique --onetime ' "$(command -v initqueue)"
+ printf -- '--name cryptroot-ask-%%k %s ' "$(command -v cryptroot-ask)"
+ # shellcheck disable=SC2016
+ printf -- '$env{DEVNAME} %s %s %s"\n' "$luksname" "$is_keysource" "$tout"
+ } >> /etc/udev/rules.d/70-luks.rules.new
+ else
+ luksname=$(dev_unit_name "$luksname")
+ # shellcheck disable=SC1003
+ luksname="$(str_replace "$luksname" '\' '\\')"
+
+ if ! crypttab_contains "$luksid"; then
+ {
+ printf -- 'ENV{ID_FS_TYPE}=="crypto_LUKS", '
+ printf -- 'ENV{ID_FS_UUID}=="*%s*", ' "$luksid"
+ printf -- 'RUN+="%s --settled --unique --onetime ' "$(command -v initqueue)"
+ printf -- '--name systemd-cryptsetup-%%k %s start ' "$(command -v systemctl)"
+ printf -- 'systemd-cryptsetup@%s.service"\n' "$luksname"
+ } >> /etc/udev/rules.d/70-luks.rules.new
+ fi
+ fi
+
+ if [ $is_keysource -eq 0 ]; then
+ uuid=$luksid
+ while [ "$uuid" != "${uuid#*-}" ]; do uuid=${uuid%%-*}${uuid#*-}; done
+ printf -- '[ -e /dev/disk/by-id/dm-uuid-CRYPT-LUKS?-*%s*-* ] || exit 1\n' "$uuid" \
+ >> "$hookdir/initqueue/finished/90-crypt.sh"
+ {
+ printf -- '[ -e /dev/disk/by-uuid/*%s* ] || ' "$luksid"
+ printf -- 'warn "crypto LUKS UUID "%s" not found"\n' "$luksid"
+ } >> "$hookdir/emergency/90-crypt.sh"
+ fi
+ done
+ elif getargbool 0 rd.auto; then
+ if [ -z "$DRACUT_SYSTEMD" ]; then
+ {
+ printf -- 'ENV{ID_FS_TYPE}=="crypto_LUKS", RUN+="%s ' "$(command -v initqueue)"
+ printf -- '--unique --settled --onetime --name cryptroot-ask-%%k '
+ # shellcheck disable=SC2016
+ printf -- '%s $env{DEVNAME} luks-$env{ID_FS_UUID} 0 %s"\n' "$(command -v cryptroot-ask)" "$tout"
+ } >> /etc/udev/rules.d/70-luks.rules.new
+ else
+ {
+ printf -- 'ENV{ID_FS_TYPE}=="crypto_LUKS", RUN+="%s ' "$(command -v initqueue)"
+ printf -- '--unique --settled --onetime --name crypt-run-generator-%%k '
+ # shellcheck disable=SC2016
+ printf -- '%s $env{DEVNAME} luks-$env{ID_FS_UUID}"\n' "$(command -v crypt-run-generator)"
+ } >> /etc/udev/rules.d/70-luks.rules.new
+ fi
+ fi
+
+ echo 'LABEL="luks_end"' >> /etc/udev/rules.d/70-luks.rules.new
+ mv /etc/udev/rules.d/70-luks.rules.new /etc/udev/rules.d/70-luks.rules
+fi
diff --git a/modules.d/90crypt/parse-keydev.sh b/modules.d/90crypt/parse-keydev.sh
new file mode 100755
index 0000000..467d892
--- /dev/null
+++ b/modules.d/90crypt/parse-keydev.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+if getargbool 1 rd.luks -n rd_NO_LUKS \
+ && [ -n "$(getarg rd.luks.key)" ]; then
+ exec 7> /etc/udev/rules.d/65-luks-keydev.rules
+ echo 'SUBSYSTEM!="block", GOTO="luks_keydev_end"' >&7
+ echo 'ACTION!="add|change", GOTO="luks_keydev_end"' >&7
+
+ for arg in $(getargs rd.luks.key); do
+ unset keypath keydev luksdev
+ splitsep : "$arg" keypath keydev luksdev
+
+ info "rd.luks.key: keypath='$keypath' keydev='$keydev' luksdev='$luksdev'"
+
+ if [ -z "$keypath" ]; then
+ warn 'keypath required!'
+ continue
+ fi
+
+ # A keydev of '/' is treated as the initrd itself
+ if [ "/" = "$keydev" ]; then
+ [ -z "$luksdev" ] && luksdev='*'
+ echo "$luksdev:$keydev:$keypath" >> /tmp/luks.keys
+ continue
+ elif [ -n "$keydev" ]; then
+ udevmatch "$keydev" >&7 || {
+ warn 'keydev incorrect!'
+ continue
+ }
+ printf ', ' >&7
+ fi
+
+ {
+ printf -- 'RUN+="%s --unique --onetime ' "$(command -v initqueue)"
+ printf -- '--name probe-keydev-%%k '
+ printf -- '%s /dev/%%k %s %s"\n' \
+ "$(command -v probe-keydev)" "${keypath}" "${luksdev}"
+ } >&7
+ done
+ unset arg keypath keydev luksdev
+
+ echo 'LABEL="luks_keydev_end"' >&7
+ exec 7>&-
+fi
diff --git a/modules.d/90crypt/probe-keydev.sh b/modules.d/90crypt/probe-keydev.sh
new file mode 100755
index 0000000..e5a3f36
--- /dev/null
+++ b/modules.d/90crypt/probe-keydev.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+. /lib/dracut-crypt-lib.sh
+
+real_keydev="$1"
+keypath="$2"
+luksdev="$3"
+
+[ -z "$real_keydev" -o -z "$keypath" ] && die 'probe-keydev: wrong usage!'
+[ -z "$luksdev" ] && luksdev='*'
+
+info "Probing $real_keydev for $keypath..."
+test_dev -f "$real_keydev" "$keypath" || exit 1
+
+info "Found $keypath on $real_keydev"
+echo "$luksdev:$real_keydev:$keypath" >> /tmp/luks.keys