Hi there, As a dropbear (in particular its remote unlocking feature) co-maintainer (see #790125) I'd like to support this :-)
This bug has just been brought to my attention and it convinced me not to make dropbear-initramfs conflict with plymouth. Solving the problem at the root seems like the way to go IMHO. Furthermore I just removed my own ‘/bin/unlock’ hack from dropbear-initramfs (never released, but enclosed here for completeness) since I like Matthias' solution better and its proper place is probably the cryptsetup package. The presence of such a script is particularly interesting with SSH since one can use ‘command=’ option of authorized_keys(5) to avoid users poking around. However I'd like to further patch ‘scripts/local-top/cryptroot’ to avoid calling $cryptkeyscript if the standard input is not a TTY. This would allow my common use-case gpg -o - --decrypt /path/to/passphrase.gpg | ssh -F ~/.luks/ssh.conf host (with ‘RequestTTY no’ in ‘~/.luks/ssh.conf’). See the updated patch enclosed. I have also changed > + for PID in $(ps | grep -e '/lib/cryptsetup/askpass' -e > 'plymouth.*ask-for-password' | sed -n -e '/grep/! { > s#[[:space:]]*\([0-9]\+\)[[:space:]]*.*#\1#p ; }') > + do > + kill -9 "${PID}" > + done to ps -eo pid,args | sed -nr "s#^\s*([0-9]+)\s+(/lib/cryptsetup/askpass|plymouth.*ask-for-password)\s+.*#\1#p" | xargs kill -9 although I'm too happy with the SIGKILL. I wish there was a cleaner way to tell these scripts to bail out, but SIGTERM doesn't seem enough for askpass. Also, I don't know what to think about hijacking the prereq to pass the argument. It might be better to use a ‘PLYMOUTH={yes/no}’ environment variable and the following two-liner as unlock script: #!/bin/sh PLYMOUTH=no exec /scripts/local-top/cryptroot Cheers, -- Guilhem.
#!/bin/sh # Remotely unlock encrypted volumes. # # Copyright © 2015 Guilhem Moulin <guil...@guilhem.org> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. set -ue PATH=/sbin:/bin TIMEOUT=10 PASSFIFO=/lib/cryptsetup/passfifo ASKPASS=/lib/cryptsetup/askpass # Return 0 if $pid has a file descriptor pointing to $name, and 1 # otherwise. in_fds() { local pid="$1" name="$2" fd for fd in $(find "/proc/$pid/fd" -type l); do [ "$(readlink -f "$fd")" != "$name" ] || return 0 done return 1 } # Print the PID of the askpass process with a file descriptor opened to # /lib/cryptsetup/passfifo. get_askpass_pid() { ps -eo pid,args | sed -nr "s#^\s*([0-9]+)\s+$ASKPASS\s+.*#\1#p" | while read pid; do if in_fds "$pid" "$PASSFIFO"; then echo "$pid" break fi done } # Wait for askpass, then set $PID (resp. $BIRTH) to the PID (resp. # birth date) of the cryptsetup process with same $CRYPTTAB_NAME. wait_for_prompt() { local pid=$(get_askpass_pid) timer=$(( 10 * $TIMEOUT )) # wait for the fifo until [ "$pid" ] && [ -p "$PASSFIFO" ]; do sleep .1 pid=$(get_askpass_pid) timer=$(( $timer - 1 )) if [ $timer -le 0 ]; then echo "Error: Timeout reached while waiting for askpass." >&2 exit 1 fi done # find the cryptsetup process with same $CRYPTTAB_NAME eval $(grep -Ez '^CRYPTTAB_(NAME|TRIED|SOURCE)=' "/proc/$pid/environ" | tr '\0' '\n') for pid in $(ps -eo pid,args | sed -nr 's#^\s*([0-9]+)\s+/sbin/cryptsetup\s+.*#\1#p'); do if grep -Fxqz "CRYPTTAB_NAME=$CRYPTTAB_NAME" "/proc/$pid/environ"; then PID=$pid BIRTH=$(stat -c'%Z' "/proc/$PID") return 0; fi done PID= BIRTH= } # Wait until $PID no longer exists or has a birth date greater that # $BIRTH (ie was reallocated). Then return with exit value 0 if # /dev/mapper/$CRYPTTAB_NAME exists, and with exit value 1 if the # maximum number of tries exceeded. Otherwise (if the unlocking # failed), return with value 1. wait_for_answer() { local timer=$(( 10 * $TIMEOUT )) until [ ! -d "/proc/$PID" ] || [ $(stat -c'%Z' "/proc/$PID") -gt $BIRTH ]; do sleep .1 timer=$(( $timer - 1 )) if [ $timer -le 0 ]; then echo "Error: Timeout reached while waiting for PID $PID." >&2 exit 1 fi done if [ -e "/dev/mapper/$CRYPTTAB_NAME" ]; then echo "cryptsetup: $CRYPTTAB_NAME set up successfully" >&2 exit 0 elif [ $CRYPTTAB_TRIED -ge 2 ]; then echo "cryptsetup: maximum number of tries exceeded for $CRYPTTAB_NAME" >&2 exit 1 else echo "cryptsetup: cryptsetup failed, bad password or options?" >&2 return 1 fi } if [ -t 0 -a -t 1 -a -x "$ASKPASS" ]; then # interactive mode on a TTY: keep trying until successfull or # maximum number of tries exceeded. while :; do wait_for_prompt diskname="$CRYPTTAB_NAME" [ "${CRYPTTAB_SOURCE#/dev/disk/by-uuid/}" != "$CRYPTTAB_SOURCE" ] || diskname="$diskname ($CRYPTTAB_SOURCE)" $ASKPASS "Please unlock disk $diskname: " >"$PASSFIFO" wait_for_answer || true done else # non-interactive mode: slurp the passphrase from stdin wait_for_prompt diskname="$CRYPTTAB_NAME" [ "${CRYPTTAB_SOURCE#/dev/disk/by-uuid/}" != "$CRYPTTAB_SOURCE" ] || diskname="$diskname ($CRYPTTAB_SOURCE)" echo "Please unlock disk $diskname" cat >"$PASSFIFO" wait_for_answer || exit 1 fi
--- /usr/share/initramfs-tools/scripts/local-top/cryptroot +++ /usr/share/initramfs-tools/scripts/local-top/cryptroot @@ -16,11 +16,15 @@ done } +NOPLYMOUTH=0 + case $1 in prereqs) prereqs exit 0 ;; +noplymouth) + NOPLYMOUTH=1 esac # source for log_*_msg() functions, see LP: #272301 @@ -31,7 +35,7 @@ # message() { - if [ -x /bin/plymouth ] && plymouth --ping; then + if [ "${NOPLYMOUTH}" -eq 0 -a -x /bin/plymouth ] && plymouth --ping; then plymouth message --text="$@" else echo "$@" >&2 @@ -285,20 +289,21 @@ diskname="$cryptsource ($crypttarget)" fi - if [ -x /bin/plymouth ] && plymouth --ping; then + if [ "${NOPLYMOUTH}" -eq 0 -a -x /bin/plymouth ] && plymouth --ping; then cryptkeyscript="plymouth ask-for-password --prompt" # Plymouth will add a : if it is a non-graphical prompt cryptkey="Please unlock disk $diskname" - else + elif [ -t 0 ]; then cryptkeyscript="/lib/cryptsetup/askpass" cryptkey="Please unlock disk $diskname: " + else + echo "Please unlock disk $diskname" fi fi - if [ ! -e "$NEWROOT" ]; then - if ! crypttarget="$crypttarget" cryptsource="$cryptsource" \ - $cryptkeyscript "$cryptkey" | $cryptopen; then + if ! { [ -n "$cryptkeyscript" ] && crypttarget="$crypttarget" cryptsource="$cryptsource" \ + $cryptkeyscript "$cryptkey" | $cryptopen || $cryptopen; }; then message "cryptsetup: cryptsetup failed, bad password or options?" continue fi @@ -309,6 +314,9 @@ return 1 fi + # Kill all remaining processes that ask for the password + ps -eo pid,args | sed -nr "s#^\s*([0-9]+)\s+(/lib/cryptsetup/askpass|plymouth.*ask-for-password)\s+.*#\1#p" | xargs kill + #FSTYPE='' #eval $(fstype < "$NEWROOT") FSTYPE="$(/sbin/blkid -s TYPE -o value "$NEWROOT")"
signature.asc
Description: PGP signature