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.
218 lines
6.7 KiB
218 lines
6.7 KiB
#!/bin/sh |
|
# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- |
|
# ex: ts=8 sw=4 sts=4 et filetype=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 l d rest |
|
if [ -f /etc/crypttab ]; then |
|
while read l d rest; do |
|
strstr "${l##luks-}" "${luks##luks-}" && return 0 |
|
strstr "$d" "${luks##luks-}" && return 0 |
|
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 cmd; local prompt; local tries=3 |
|
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 "$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=$(mkuniqdir /mnt testdev) |
|
local path |
|
|
|
[ -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 |
|
|
|
local IFS=: |
|
while read luks_dev key_dev key_path; 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" |
|
|
|
# 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="/mnt/$(str_replace "keydev-$keydev-$keypath" '/' '-')" |
|
|
|
if [ ! -d "$mntp" ]; then |
|
mkdir "$mntp" |
|
mount -r "$keydev" "$mntp" || die 'Mounting rem. dev. failed!' |
|
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" |
|
initqueue --onetime --finished --unique --name "crypt-loop-cleanup-99-${mntp##*/}" \ |
|
$(command -v umount) "$mntp; " $(command -v rmdir) "$mntp" |
|
return 0 |
|
else |
|
die "No loop file support to decrypt '$keypath' on '$keydev'." |
|
fi |
|
;; |
|
*) cat "$mntp/$keypath" ;; |
|
esac |
|
|
|
# General unmounting mechanism, modules doing custom cleanup should return earlier |
|
# and install a pre-pivot cleanup hook |
|
umount "$mntp" |
|
rmdir "$mntp" |
|
}
|
|
|