1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
|
#!/bin/sh
PREREQ="cryptroot-prepare"
#
# Standard initramfs preamble
#
prereqs() {
# Make sure that cryptroot is run last in local-top
local req script="${0##*/}" dir
dir="$DESTDIR/scripts/${CRYPTROOT_STAGE-local-top}"
for req in "$dir"/*; do
test -x "$req" || continue
req="${req##*/}"
if [ "$req" != "$script" ]; then
printf '%s\n' "$req"
fi
done
}
case $1 in
prereqs)
prereqs
exit 0
;;
esac
. /scripts/functions
[ -f /lib/cryptsetup/functions ] || return 0
. /lib/cryptsetup/functions
# wait_for_source()
# Wait for encrypted $CRYPTTAB_SOURCE . Set $CRYPTTAB_SOURCE
# to its normalized device name when it shows up;
# return 1 if timeout.
wait_for_source() {
wait_for_udev 10
if crypttab_resolve_source; then
# the device is here already, no need to loop
return 0
fi
# If the source device hasn't shown up yet, give it a little while
# to allow for asynchronous device discovery (e.g. USB).
#
# We also need to take into account RAID or other devices that may
# only be available on local-block stage. So, wait 5 seconds upfront,
# in local-top; if that fails, end execution relying on local-block
# invocations. Allow $ROOTDELAY/4 invocations with 1s sleep times (with
# a minimum of 20 invocations), and if after that we still fail, then it's
# really time to give-up. Variable $initrd_cnt tracks the re-invocations.
#
# Part of the lines below has been taken from initramfs-tools
# scripts/local's local_device_setup(), as suggested per
# https://launchpad.net/bugs/164044 .
local slumber=5
if [ "${CRYPTROOT_STAGE-}" = "local-block" ]; then
slumber=1
fi
cryptsetup_message "Waiting for encrypted source device $CRYPTTAB_SOURCE..."
while [ $slumber -gt 0 ]; do
sleep 1
if crypttab_resolve_source; then
wait_for_udev 10
return 0
fi
slumber=$(( $slumber - 1 ))
done
return 1
}
# setup_mapping()
# Set up a crypttab(5) mapping defined by $CRYPTTAB_NAME,
# $CRYPTTAB_SOURCE, $CRYPTTAB_KEY, $CRYPTTAB_OPTIONS.
setup_mapping() {
local dev initrd_cnt
# We control here the number of re-invocations of this script from
# local-block - the heuristic is $ROOTDELAY/4, with a minimum of 20.
if [ -f "$CRYPTROOT_COUNT_FILE" ]; then
initrd_cnt="$(cat <"$CRYPTROOT_COUNT_FILE")"
else
initrd_cnt="${ROOTDELAY:-180}"
initrd_cnt=$(( initrd_cnt/4 ))
if [ $initrd_cnt -lt 20 ]; then
initrd_cnt=20
fi
echo "$initrd_cnt" >"$CRYPTROOT_COUNT_FILE"
fi
# The same target can be specified multiple times
# e.g. root and resume lvs-on-lvm-on-crypto
if dm_blkdevname "$CRYPTTAB_NAME" >/dev/null; then
return 0
fi
crypttab_parse_options --export --missing-path=fail || return 1
if ! wait_for_source; then
if [ $initrd_cnt -eq 0 ]; then
# we've given up
if [ -n "$panic" ]; then
panic "ALERT! encrypted source device $CRYPTTAB_SOURCE does not exist, can't unlock $CRYPTTAB_NAME."
else
# let the user fix matters if they can
echo " ALERT! encrypted source device $CRYPTTAB_SOURCE does not exist, can't unlock $CRYPTTAB_NAME."
echo " Check cryptopts=source= bootarg: cat /proc/cmdline"
echo " or missing modules, devices: cat /proc/modules; ls /dev"
panic "Dropping to a shell."
fi
return 1 # can't continue because environment is lost
else
initrd_cnt=$(( initrd_cnt - 1 ))
echo "$initrd_cnt" >"$CRYPTROOT_COUNT_FILE"
return 0 # allow some attempts on local-block stage
fi
fi
# our `cryptroot-unlock` script searches for cryptsetup processes
# with a given CRYPTTAB_NAME it their environment
export CRYPTTAB_NAME
if [ -z "${CRYPTTAB_OPTION_keyscript+x}" ]; then
# no keyscript: interactive unlocking, or key file
if [ "${CRYPTTAB_KEY#/FIXME-initramfs-rootmnt/}" != "$CRYPTTAB_KEY" ]; then
# skip the mapping for now if the root FS is not mounted yet
sed -rn 's/^\s*[^#[:blank:]]\S*\s+(\S+)\s.*/\1/p' /proc/mounts | grep -Fxq -- "$rootmnt" || return 1
# substitute the "/FIXME-initramfs-rootmnt/" prefix by the real root FS mountpoint otherwise
CRYPTTAB_KEY="$rootmnt/${CRYPTTAB_KEY#/FIXME-initramfs-rootmnt/}"
fi
if [ "$CRYPTTAB_KEY" != "none" ]; then
if [ ! -e "$CRYPTTAB_KEY" ]; then
cryptsetup_message "ERROR: Skipping target $CRYPTTAB_NAME: non-existing key file $CRYPTTAB_KEY"
return 1
fi
# try only once if we have a key file
CRYPTTAB_OPTION_tries=1
fi
fi
local count=0 maxtries="${CRYPTTAB_OPTION_tries:-3}" fstype vg rv
while [ $maxtries -le 0 ] || [ $count -lt $maxtries ]; do
if [ -z "${CRYPTTAB_OPTION_keyscript+x}" ] && [ "$CRYPTTAB_KEY" != "none" ]; then
# unlock via keyfile
unlock_mapping "$CRYPTTAB_KEY"
else
# unlock interactively or via keyscript
run_keyscript "$count" | unlock_mapping
fi
rv=$?
count=$(( $count + 1 ))
if [ $rv -ne 0 ]; then
cryptsetup_message "ERROR: $CRYPTTAB_NAME: cryptsetup failed, bad password or options?"
sleep 1
continue
elif ! dev="$(dm_blkdevname "$CRYPTTAB_NAME")"; then
cryptsetup_message "ERROR: $CRYPTTAB_NAME: unknown error setting up device mapping"
return 1
fi
if ! fstype="$(get_fstype "$dev")" || [ "$fstype" = "unknown" ]; then
if [ "$CRYPTTAB_TYPE" != "luks" ]; then
# bad password for plain dm-crypt device? or mkfs not run yet?
cryptsetup_message "ERROR: $CRYPTTAB_NAME: unknown fstype, bad password or options?"
wait_for_udev 10
/sbin/cryptsetup remove -- "$CRYPTTAB_NAME"
sleep 1
continue
fi
fi
cryptsetup_message "$CRYPTTAB_NAME: set up successfully"
wait_for_udev 10
return 0
done
cryptsetup_message "ERROR: $CRYPTTAB_NAME: maximum number of tries exceeded"
exit 1
}
#######################################################################
# Begin real processing
mkdir -p /cryptroot # might not exist yet if the main system has no crypttab(5)
# Do we have any kernel boot arguments?
if ! grep -qE '^(.*\s)?cryptopts=' /proc/cmdline; then
# ensure $TABFILE exists and has a mtime greater than the boot time
# (existing $TABFILE is preserved)
touch -- "$TABFILE"
else
# let the read builtin unescape the '\' as GRUB substitutes '\' by '\\' in the cmdline
tr ' ' '\n' </proc/cmdline | sed -n 's/^cryptopts=//p' | while IFS= read cryptopts; do
# skip empty values (which can be used to disable the initramfs
# scripts for a particular boot, cf. #873840)
[ -n "$cryptopts" ] || continue
unset -v target source key options
IFS=","
for x in $cryptopts; do
case "$x" in
target=*) target="${x#target=}";;
source=*) source="${x#source=}";;
key=*) key="${x#key=}";;
*) options="${options+$options,}$x";;
esac
done
if [ -z "${source:+x}" ]; then
cryptsetup_message "ERROR: Missing source= value in kernel parameter cryptopts=$cryptopts"
else
# preserve mangling
printf '%s %s %s %s\n' "${target:-cryptroot}" "$source" "${key:-none}" "${options-}"
fi
done >"$TABFILE"
fi
# Do we have any settings from the $TABFILE?
if [ -s "$TABFILE" ]; then
# Create locking directory before invoking cryptsetup(8) to avoid warnings
mkdir -pm0700 /run/cryptsetup
modprobe -q dm_crypt
crypttab_foreach_entry setup_mapping
fi
exit 0
|