You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

205 lines
5.3 KiB

#!/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
crypt: Prevent asking for password multiple times if non-default crypt name is used. If a non-default device mapper name is used for an encrypted partion is used, (i.e. not luks-$UUID) due to parsing of /etc/crypttab, then the short-circuits put in place to prevent asking the password twice do not work. This would not normally be an issue as the settled job itself should be removed after it has run and thus cannot be run again. Sadly, due to the corresponding udev rule using ACTION="add|changed", and the fact that trying to unlock the device (whether successful or not) seems to trigger a changed event, it means the settled job is recreated with each itteration thus causing the whole loop to run again. It is this situation that the short-circuit exits would normally come into play but sadly do not work when non-standard names are used. By the time the /tmp/cryptroot-asked-$2 file is written near the end of the script, the value of $2 has already been lost due to the argument parsing code's use of 'shift'. So while on systems where the default name is used are protected by checking /dev/mapper/xxxx, the /tmp/cryptroot-asked-$2 file didn't help on systems where this was not used due to this bug. So this commit shuffles things around somewhat such that: 1. The /dev/mapper/xxxx device is checked *after* resolving $2 (which contains the default name) to whatever /etc/crypttab specifies. 2. The cryptroot-asked-xxxx file also uses the translated name both for the initial check and to flag when it's written. As a separate fix, it might make sense to change the udev rule to only act on add events rather than add|change events, but I'm not sure of the ramifications of such a change and there may be cases where the add event is missed and thus the change event needs to be included.
11 years ago
. /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
crypt: Prevent asking for password multiple times if non-default crypt name is used. If a non-default device mapper name is used for an encrypted partion is used, (i.e. not luks-$UUID) due to parsing of /etc/crypttab, then the short-circuits put in place to prevent asking the password twice do not work. This would not normally be an issue as the settled job itself should be removed after it has run and thus cannot be run again. Sadly, due to the corresponding udev rule using ACTION="add|changed", and the fact that trying to unlock the device (whether successful or not) seems to trigger a changed event, it means the settled job is recreated with each itteration thus causing the whole loop to run again. It is this situation that the short-circuit exits would normally come into play but sadly do not work when non-standard names are used. By the time the /tmp/cryptroot-asked-$2 file is written near the end of the script, the value of $2 has already been lost due to the argument parsing code's use of 'shift'. So while on systems where the default name is used are protected by checking /dev/mapper/xxxx, the /tmp/cryptroot-asked-$2 file didn't help on systems where this was not used due to this bug. So this commit shuffles things around somewhat such that: 1. The /dev/mapper/xxxx device is checked *after* resolving $2 (which contains the default name) to whatever /etc/crypttab specifies. 2. The cryptroot-asked-xxxx file also uses the translated name both for the initial check and to flag when it's written. As a separate fix, it might make sense to change the udev rule to only act on add events rather than add|change events, but I'm not sure of the ramifications of such a change and there may be cases where the add event is missed and thus the change event needs to be included.
11 years ago
# 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 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
crypt: Prevent asking for password multiple times if non-default crypt name is used. If a non-default device mapper name is used for an encrypted partion is used, (i.e. not luks-$UUID) due to parsing of /etc/crypttab, then the short-circuits put in place to prevent asking the password twice do not work. This would not normally be an issue as the settled job itself should be removed after it has run and thus cannot be run again. Sadly, due to the corresponding udev rule using ACTION="add|changed", and the fact that trying to unlock the device (whether successful or not) seems to trigger a changed event, it means the settled job is recreated with each itteration thus causing the whole loop to run again. It is this situation that the short-circuit exits would normally come into play but sadly do not work when non-standard names are used. By the time the /tmp/cryptroot-asked-$2 file is written near the end of the script, the value of $2 has already been lost due to the argument parsing code's use of 'shift'. So while on systems where the default name is used are protected by checking /dev/mapper/xxxx, the /tmp/cryptroot-asked-$2 file didn't help on systems where this was not used due to this bug. So this commit shuffles things around somewhat such that: 1. The /dev/mapper/xxxx device is checked *after* resolving $2 (which contains the default name) to whatever /etc/crypttab specifies. 2. The cryptroot-asked-xxxx file also uses the translated name both for the initial check and to flag when it's written. As a separate fix, it might make sense to change the udev rule to only act on add events rather than add|change events, but I'm not sure of the ramifications of such a change and there may be cases where the add event is missed and thus the change event needs to be included.
11 years ago
# 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
crypt: Prevent asking for password multiple times if non-default crypt name is used. If a non-default device mapper name is used for an encrypted partion is used, (i.e. not luks-$UUID) due to parsing of /etc/crypttab, then the short-circuits put in place to prevent asking the password twice do not work. This would not normally be an issue as the settled job itself should be removed after it has run and thus cannot be run again. Sadly, due to the corresponding udev rule using ACTION="add|changed", and the fact that trying to unlock the device (whether successful or not) seems to trigger a changed event, it means the settled job is recreated with each itteration thus causing the whole loop to run again. It is this situation that the short-circuit exits would normally come into play but sadly do not work when non-standard names are used. By the time the /tmp/cryptroot-asked-$2 file is written near the end of the script, the value of $2 has already been lost due to the argument parsing code's use of 'shift'. So while on systems where the default name is used are protected by checking /dev/mapper/xxxx, the /tmp/cryptroot-asked-$2 file didn't help on systems where this was not used due to this bug. So this commit shuffles things around somewhat such that: 1. The /dev/mapper/xxxx device is checked *after* resolving $2 (which contains the default name) to whatever /etc/crypttab specifies. 2. The cryptroot-asked-xxxx file also uses the translated name both for the initial check and to flag when it's written. As a separate fix, it might make sense to change the udev rule to only act on add events rather than add|change events, but I'm not sure of the ramifications of such a change and there may be cases where the add event is missed and thus the change event needs to be included.
11 years ago
# 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=,
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
crypt: Prevent asking for password multiple times if non-default crypt name is used. If a non-default device mapper name is used for an encrypted partion is used, (i.e. not luks-$UUID) due to parsing of /etc/crypttab, then the short-circuits put in place to prevent asking the password twice do not work. This would not normally be an issue as the settled job itself should be removed after it has run and thus cannot be run again. Sadly, due to the corresponding udev rule using ACTION="add|changed", and the fact that trying to unlock the device (whether successful or not) seems to trigger a changed event, it means the settled job is recreated with each itteration thus causing the whole loop to run again. It is this situation that the short-circuit exits would normally come into play but sadly do not work when non-standard names are used. By the time the /tmp/cryptroot-asked-$2 file is written near the end of the script, the value of $2 has already been lost due to the argument parsing code's use of 'shift'. So while on systems where the default name is used are protected by checking /dev/mapper/xxxx, the /tmp/cryptroot-asked-$2 file didn't help on systems where this was not used due to this bug. So this commit shuffles things around somewhat such that: 1. The /dev/mapper/xxxx device is checked *after* resolving $2 (which contains the default name) to whatever /etc/crypttab specifies. 2. The cryptroot-asked-xxxx file also uses the translated name both for the initial check and to flag when it's written. As a separate fix, it might make sense to change the udev rule to only act on add events rather than add|change events, but I'm not sure of the ramifications of such a change and there may be cases where the add event is missed and thus the change event needs to be included.
11 years ago
# fallback to passphrase
ask_passphrase=1
if [ -n "$luksfile" -a "$luksfile" != "none" -a -e "$luksfile" ]; then
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'"
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