From 724d6a6bf0ecf149f41f3f816be3c5d45c02881d Mon Sep 17 00:00:00 2001 From: Julien Coloos Date: Sun, 22 Nov 2015 18:53:37 +0100 Subject: [PATCH] Handle optional ipconfig timeout Specify timeout for ipconfig so that we can still boot while network is done. Otherwise ipconfig remains stuck (until IP can be configured). If not given we default to 10s. Minor code refactoring. Moved configuration file from /etc/dropbear/initrd.env to /etc/initcpio/sshcs_env since it now contains options for ipconfig and not only dropbear. Package installation script move legacy file to new path if present. v0.3-1 --- PKGBUILD | 6 +- README.md | 5 +- initrd-ssh-cryptsetup.install | 9 +++ src/hooks/ssh-cryptsetup | 101 ++++++++++++++++++++-------------- src/install/ssh-cryptsetup | 10 +++- 5 files changed, 84 insertions(+), 47 deletions(-) diff --git a/PKGBUILD b/PKGBUILD index 869e45f..3e81136 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -1,6 +1,6 @@ # Maintainer: Julien Coloos pkgname=initrd-ssh-cryptsetup -pkgver=0.2 +pkgver=0.3 pkgrel=1 pkgdesc="Allows for LUKS-encrypted devices to be unlocked remotely over SSH" arch=('any') @@ -10,8 +10,8 @@ depends=('dropbear' 'cryptsetup' 'mkinitcpio-nfs-utils' 'iproute2') install=$pkgname.install changelog='ChangeLog' source=("http://julien.coloos.free.fr/archlinux/$pkgname-$pkgver.tar.xz" "$pkgname.install") -md5sums=('27b040fd69d252050c20a2595f8c67ba' - 'a703663472bbd50882a11f6b2cfccbf0') +md5sums=('a25dbbac5cd82a8d87932e646e38d9c4' + 'ac60109d80e7bb2af0d66e69aaf178a6') package() { install -Dm644 "$srcdir/src/install/ssh-cryptsetup" "$pkgdir/usr/lib/initcpio/install/ssh-cryptsetup" diff --git a/README.md b/README.md index 926f45a..3a85873 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,9 @@ As explained upon installation, the following things need to be done: The LUKS-encrypted devices to unlock are derived from `/etc/crypttab`. -Some options can be set in `/etc/dropbear/initrd.env` (file is sourced in initrd shell): +Some options can be set in `/etc/initcpio/sshcs_env` (file is sourced in initrd shell): + * `sshcs_opt_timeout_ipconfig`: time (in seconds) to configure IP + - default: 10 seconds * `sshcs_opt_listen`: SSH listening port - default: 22 * `sshcs_opt_timeout_poweroff`: time (in seconds) to unlock devices before automatic powering off @@ -24,6 +26,7 @@ Some options can be set in `/etc/dropbear/initrd.env` (file is sourced in initrd For example: + sshcs_opt_timeout_ipconfig=30 sshcs_opt_listen=2222 sshcs_opt_timeout_poweroff=-1 diff --git a/initrd-ssh-cryptsetup.install b/initrd-ssh-cryptsetup.install index cf21d41..27b9f2f 100644 --- a/initrd-ssh-cryptsetup.install +++ b/initrd-ssh-cryptsetup.install @@ -1,8 +1,17 @@ #!/bin/bash post_install() { + local sshcs_env="/etc/initcpio/sshcs_env" + local sshcs_env_old="/etc/dropbear/initrd.env" local dropbear_authorized_keys="/etc/dropbear/initrd.authorized_keys" local etc_dropbear=$(dirname "${dropbear_authorized_keys}") + [ ! -e "${sshcs_env}" ] && [ -e "${sshcs_env_old}" ] && { + [ -d $(dirname "${sshcs_env}") ] || mkdir -p $(dirname "${sshcs_env}") + mv "${sshcs_env_old}" "${sshcs_env}" + cat < "${net_env}" - ipconfig "ip=${ip}" | while read line; do + + echo "" + echo "Configuring IP (timeout = ${sshcs_opt_timeout_ipconfig}s) ..." + ipconfig_out=$(ipconfig -t "${sshcs_opt_timeout_ipconfig}" "ip=${ip}") + if [ $? -ne 0 ]; then + err "IP configuration timeout!" + return 1 + fi + + echo -n "${ipconfig_out}" | while read line; do [ "${line#"IP-Config:"}" != "${line}" ] && continue line="$(echo "${line}" | sed -e 's/ :/:/g;s/: /=/g')" @@ -36,6 +56,14 @@ sshcs_net_start() { [ -n "${net_address}" ] } +sshcs_net_done() { + # we are done with the network + if [ -n "${net_device}" ]; then + ip addr flush dev "${net_device}" + ip link set dev "${net_device}" down + fi +} + sshcs_trapped_timeout() { err "Timeout reached! Powering off." poweroff -f @@ -68,8 +96,16 @@ sshcs_untrap_timeout() { msg "Timeout cleared." } +sshcs_unlock() { + sshcs_trap_timeout + + # actual script (shared with SSH login) unlocking encrypted devices + . "${sshcs_cryptsetup_script}" + + sshcs_untrap_timeout +} + sshcs_dropbear_unlock() { - local timeout_poweroff_min=120 local pid_timeout= local dev_pts_mounted=0 local listen= @@ -91,14 +127,14 @@ sshcs_dropbear_unlock() { . "/init_functions" -if [ ! -f "${dropbear_cryptsetup_script}" ]; then +if [ ! -f "${sshcs_cryptsetup_script}" ]; then err "No cryptsetup script present! Please retry." exit 0 fi if [ -c "/dev/mapper/control" ]; then CSQUIET= - . "${dropbear_cryptsetup_script}" + . "${sshcs_cryptsetup_script}" echo "" echo "cryptsetup succeeded! Boot sequence should go on." @@ -113,21 +149,11 @@ EOF [ ! -d "/var/log" ] && mkdir -p "/var/log" touch "/var/log/lastlog" - [ -e "${dropbear_env}" ] && . "${dropbear_env}" - [ -n "${sshcs_opt_listen}" ] && sshcs_opt_listen="-p ${sshcs_opt_listen}" - [ -z "${sshcs_opt_timeout_poweroff}" ] && sshcs_opt_timeout_poweroff=${timeout_poweroff_min} - [ ${sshcs_opt_timeout_poweroff} -ge 0 ] && [ ${sshcs_opt_timeout_poweroff} -lt ${timeout_poweroff_min} ] && sshcs_opt_timeout_poweroff=${timeout_poweroff_min} - - msg "Starting dropbear ..." dropbear -Emsgjk -P "${path_dropbear_pid}" ${sshcs_opt_listen} - sshcs_trap_timeout - - # actual script (shared with SSH login) unlocking encrypted devices - . "${dropbear_cryptsetup_script}" - - sshcs_untrap_timeout + # Actual unlocking + sshcs_unlock # cleanup dropbear if [ -f "${path_dropbear_pid}" ]; then @@ -135,7 +161,7 @@ EOF kill $(cat "${path_dropbear_pid}") rm -f "${path_dropbear_pid}" fi - rm -f "${dropbear_cryptsetup_script}" "${dropbear_login_shell}" "/etc/passwd" "/etc/shells" "/var/log/lastlog" + rm -f "${sshcs_cryptsetup_script}" "${dropbear_login_shell}" "/etc/passwd" "/etc/shells" "/var/log/lastlog" # cleanup /dev/pts if necessary if [ ${dev_pts_mounted} -ne 0 ]; then @@ -144,14 +170,6 @@ EOF fi } -sshcs_net_done() { - # we are done with the network - if [ -n "${net_device}" ]; then - ip addr flush dev "${net_device}" - ip link set dev "${net_device}" down - fi -} - sshcs_cryptpart_process() { # ensure there is a device (handle 'UUID=' format) [ -z "${cryptdev}" ] && return 0 @@ -180,7 +198,7 @@ sshcs_cryptpart_process() { if cryptsetup isLuks "${cryptdev}" >/dev/null 2>&1; then # update script used to unlock device either in console or SSH - [ -s "${dropbear_cryptsetup_script}" ] || cat < "${dropbear_cryptsetup_script}" + [ -s "${sshcs_cryptsetup_script}" ] || cat < "${sshcs_cryptsetup_script}" cycle_or_retry() { local res @@ -194,7 +212,7 @@ cycle_or_retry() { } EOF - cat <> "${dropbear_cryptsetup_script}" + cat <> "${sshcs_cryptsetup_script}" # loop until device is available while [ ! -e "/dev/mapper/${cryptname}" ]; do if cryptsetup open --type "${crypttype}" "${cryptdev}" "${cryptname}" "${cryptargs}" "\${CSQUIET}"; then @@ -220,14 +238,17 @@ EOF run_hook() { local etc_crypttab="/etc/crypttab" - local dropbear_env="/etc/dropbear/initrd.env" + local sshcs_env="/etc/initcpio/sshcs_env" local path_dropbear_pid="/.dropbear.pid" local dropbear_login_shell="/.cryptsetup_shell.sh" - local dropbear_cryptsetup_script="/.cryptsetup_script.sh" + local sshcs_cryptsetup_script="/.cryptsetup_script.sh" local net_env="/.net_env.sh" - local line iparg net_address net_netmask net_gateway net_dns0 net_dns1 + local line iparg net_address net_device ipconfig_out net_netmask net_gateway net_dns0 net_dns1 local cryptdev cryptdev_orig crypttype cryptname cryptpass cryptoptions cryptopt cryptargs CSQUIET + # Load our options + sshcs_env_load + # sanity check: crypttab should be present [ ! -e "${etc_crypttab}" ] && return 0 @@ -236,14 +257,6 @@ run_hook() { umask 0022 - # start and check network - if ! sshcs_net_start; then - err "Net interface not available! Skipping crypt remote unlocking." - # stop the network if possible - sshcs_net_done - return 0 - fi - # check encrypted devices to handle cryptdev= crypttype=luks @@ -256,9 +269,17 @@ run_hook() { sshcs_cryptpart_process done < "${etc_crypttab}" - if [ ! -e "${dropbear_cryptsetup_script}" ]; then + if [ ! -e "${sshcs_cryptsetup_script}" ]; then err "No encrypted device found! Skipping crypt remote unlocking." - # don't forget to stop the network + return 0 + fi + + # start and check network + if ! sshcs_net_start; then + err "Net interface not available! Skipping crypt remote unlocking." + # We still allow to unlock locally with timeout + sshcs_unlock + # stop the network if possible sshcs_net_done return 0 fi diff --git a/src/install/ssh-cryptsetup b/src/install/ssh-cryptsetup index 59cc929..28d7fd4 100644 --- a/src/install/ssh-cryptsetup +++ b/src/install/ssh-cryptsetup @@ -31,7 +31,7 @@ sshcs_check_keys() { build() { local etc_crypttab="/etc/crypttab" local dropbear_authorized_keys="/etc/dropbear/initrd.authorized_keys" - local dropbear_env="/etc/dropbear/initrd.env" + local sshcs_env="/etc/initcpio/sshcs_env" local dropbear_key_types=( "dss" "rsa" "ecdsa" ) local dropbear_keyfile_prefix="/etc/dropbear/dropbear_" local dropbear_keyfile_suffix="_host_key" @@ -71,12 +71,14 @@ build() { add_binary "ip" add_binary "/usr/lib/initcpio/ipconfig" "/sbin/ipconfig" + # Our hook files + [ -e "${sshcs_env}" ] && add_file "${sshcs_env}" + # auth-related files add_file "/lib/libnss_files.so" # SSH-related files add_file "${dropbear_authorized_keys}" "/root/.ssh/authorized_keys" - [ -e "${dropbear_env}" ] && add_file "${dropbear_env}" add_file "/etc/dropbear/dropbear_rsa_host_key" add_file "/etc/dropbear/dropbear_dss_host_key" add_file "/etc/dropbear/dropbear_ecdsa_host_key" @@ -101,8 +103,10 @@ Network is configured with 'ip=' kernel parameter (see 'mkinitcpio-nfs-utils'). Authorized SSH key(s) must be present in '/etc/dropbear/initrd.authorized_keys'. LUKS encrypted devices to unlock are derived from '/etc/crypttab', which must be present. -Some options can be set in '/etc/dropbear/initrd.env' (file is sourced in +Some options can be set in '/etc/initcpio/sshcs_env' (file is sourced in initrd shell): + * 'sshcs_opt_timeout_ipconfig': time (s) to configure IP + - default: 10 seconds * 'sshcs_opt_listen': listening port (22 by default) * 'sshcs_opt_timeout_poweroff': time (s) to unlock devices before automatic powering off