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
master
Julien Coloos 2015-11-22 18:53:37 +01:00
parent b61e50ebe8
commit 724d6a6bf0
5 changed files with 84 additions and 47 deletions

View File

@ -1,6 +1,6 @@
# Maintainer: Julien Coloos <julien.coloos [at] gmail [dot] com> # Maintainer: Julien Coloos <julien.coloos [at] gmail [dot] com>
pkgname=initrd-ssh-cryptsetup pkgname=initrd-ssh-cryptsetup
pkgver=0.2 pkgver=0.3
pkgrel=1 pkgrel=1
pkgdesc="Allows for LUKS-encrypted devices to be unlocked remotely over SSH" pkgdesc="Allows for LUKS-encrypted devices to be unlocked remotely over SSH"
arch=('any') arch=('any')
@ -10,8 +10,8 @@ depends=('dropbear' 'cryptsetup' 'mkinitcpio-nfs-utils' 'iproute2')
install=$pkgname.install install=$pkgname.install
changelog='ChangeLog' changelog='ChangeLog'
source=("http://julien.coloos.free.fr/archlinux/$pkgname-$pkgver.tar.xz" "$pkgname.install") source=("http://julien.coloos.free.fr/archlinux/$pkgname-$pkgver.tar.xz" "$pkgname.install")
md5sums=('27b040fd69d252050c20a2595f8c67ba' md5sums=('a25dbbac5cd82a8d87932e646e38d9c4'
'a703663472bbd50882a11f6b2cfccbf0') 'ac60109d80e7bb2af0d66e69aaf178a6')
package() { package() {
install -Dm644 "$srcdir/src/install/ssh-cryptsetup" "$pkgdir/usr/lib/initcpio/install/ssh-cryptsetup" install -Dm644 "$srcdir/src/install/ssh-cryptsetup" "$pkgdir/usr/lib/initcpio/install/ssh-cryptsetup"

View File

@ -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`. 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 * `sshcs_opt_listen`: SSH listening port
- default: 22 - default: 22
* `sshcs_opt_timeout_poweroff`: time (in seconds) to unlock devices before automatic powering off * `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: For example:
sshcs_opt_timeout_ipconfig=30
sshcs_opt_listen=2222 sshcs_opt_listen=2222
sshcs_opt_timeout_poweroff=-1 sshcs_opt_timeout_poweroff=-1

View File

@ -1,8 +1,17 @@
#!/bin/bash #!/bin/bash
post_install() { 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 dropbear_authorized_keys="/etc/dropbear/initrd.authorized_keys"
local etc_dropbear=$(dirname "${dropbear_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 <<EOF
Moved legacy file ${sshcs_env_old} to new path ${sshcs_env}"
EOF
}
[ -d "${etc_dropbear}" ] || mkdir -p "${etc_dropbear}" [ -d "${etc_dropbear}" ] || mkdir -p "${etc_dropbear}"
[ -e "${dropbear_authorized_keys}" ] || touch "${dropbear_authorized_keys}" [ -e "${dropbear_authorized_keys}" ] || touch "${dropbear_authorized_keys}"
chmod 600 "${dropbear_authorized_keys}" chmod 600 "${dropbear_authorized_keys}"

View File

@ -1,5 +1,16 @@
#!/usr/bin/ash #!/usr/bin/ash
sshcs_env_load() {
local timeout_ipconfig_default=10
local timeout_poweroff_min=120
[ -e "${sshcs_env}" ] && . "${sshcs_env}"
[ -z "${sshcs_opt_timeout_ipconfig}" ] && sshcs_opt_timeout_ipconfig=${timeout_ipconfig_default}
[ -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}
}
sshcs_net_start() { sshcs_net_start() {
# we must have an 'ip' setting, and a device in it # we must have an 'ip' setting, and a device in it
[ -z "${ip}" ] && [ -n "${nfsaddrs}" ] && ip="${nfsaddrs}" [ -z "${ip}" ] && [ -n "${nfsaddrs}" ] && ip="${nfsaddrs}"
@ -14,7 +25,16 @@ sshcs_net_start() {
# temporary file and 'source' it since '... | while read ...' spawns a # temporary file and 'source' it since '... | while read ...' spawns a
# subshell from which outer variables cannot be altered. # subshell from which outer variables cannot be altered.
: > "${net_env}" : > "${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#"IP-Config:"}" != "${line}" ] && continue
line="$(echo "${line}" | sed -e 's/ :/:/g;s/: /=/g')" line="$(echo "${line}" | sed -e 's/ :/:/g;s/: /=/g')"
@ -36,6 +56,14 @@ sshcs_net_start() {
[ -n "${net_address}" ] [ -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() { sshcs_trapped_timeout() {
err "Timeout reached! Powering off." err "Timeout reached! Powering off."
poweroff -f poweroff -f
@ -68,8 +96,16 @@ sshcs_untrap_timeout() {
msg "Timeout cleared." 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() { sshcs_dropbear_unlock() {
local timeout_poweroff_min=120
local pid_timeout= local pid_timeout=
local dev_pts_mounted=0 local dev_pts_mounted=0
local listen= local listen=
@ -91,14 +127,14 @@ sshcs_dropbear_unlock() {
. "/init_functions" . "/init_functions"
if [ ! -f "${dropbear_cryptsetup_script}" ]; then if [ ! -f "${sshcs_cryptsetup_script}" ]; then
err "No cryptsetup script present! Please retry." err "No cryptsetup script present! Please retry."
exit 0 exit 0
fi fi
if [ -c "/dev/mapper/control" ]; then if [ -c "/dev/mapper/control" ]; then
CSQUIET= CSQUIET=
. "${dropbear_cryptsetup_script}" . "${sshcs_cryptsetup_script}"
echo "" echo ""
echo "cryptsetup succeeded! Boot sequence should go on." echo "cryptsetup succeeded! Boot sequence should go on."
@ -113,21 +149,11 @@ EOF
[ ! -d "/var/log" ] && mkdir -p "/var/log" [ ! -d "/var/log" ] && mkdir -p "/var/log"
touch "/var/log/lastlog" 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 ..." msg "Starting dropbear ..."
dropbear -Emsgjk -P "${path_dropbear_pid}" ${sshcs_opt_listen} dropbear -Emsgjk -P "${path_dropbear_pid}" ${sshcs_opt_listen}
sshcs_trap_timeout # Actual unlocking
sshcs_unlock
# actual script (shared with SSH login) unlocking encrypted devices
. "${dropbear_cryptsetup_script}"
sshcs_untrap_timeout
# cleanup dropbear # cleanup dropbear
if [ -f "${path_dropbear_pid}" ]; then if [ -f "${path_dropbear_pid}" ]; then
@ -135,7 +161,7 @@ EOF
kill $(cat "${path_dropbear_pid}") kill $(cat "${path_dropbear_pid}")
rm -f "${path_dropbear_pid}" rm -f "${path_dropbear_pid}"
fi 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 # cleanup /dev/pts if necessary
if [ ${dev_pts_mounted} -ne 0 ]; then if [ ${dev_pts_mounted} -ne 0 ]; then
@ -144,14 +170,6 @@ EOF
fi 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() { sshcs_cryptpart_process() {
# ensure there is a device (handle 'UUID=' format) # ensure there is a device (handle 'UUID=' format)
[ -z "${cryptdev}" ] && return 0 [ -z "${cryptdev}" ] && return 0
@ -180,7 +198,7 @@ sshcs_cryptpart_process() {
if cryptsetup isLuks "${cryptdev}" >/dev/null 2>&1; then if cryptsetup isLuks "${cryptdev}" >/dev/null 2>&1; then
# update script used to unlock device either in console or SSH # update script used to unlock device either in console or SSH
[ -s "${dropbear_cryptsetup_script}" ] || cat <<EOF > "${dropbear_cryptsetup_script}" [ -s "${sshcs_cryptsetup_script}" ] || cat <<EOF > "${sshcs_cryptsetup_script}"
cycle_or_retry() { cycle_or_retry() {
local res local res
@ -194,7 +212,7 @@ cycle_or_retry() {
} }
EOF EOF
cat <<EOF >> "${dropbear_cryptsetup_script}" cat <<EOF >> "${sshcs_cryptsetup_script}"
# loop until device is available # loop until device is available
while [ ! -e "/dev/mapper/${cryptname}" ]; do while [ ! -e "/dev/mapper/${cryptname}" ]; do
if cryptsetup open --type "${crypttype}" "${cryptdev}" "${cryptname}" "${cryptargs}" "\${CSQUIET}"; then if cryptsetup open --type "${crypttype}" "${cryptdev}" "${cryptname}" "${cryptargs}" "\${CSQUIET}"; then
@ -220,14 +238,17 @@ EOF
run_hook() { run_hook() {
local etc_crypttab="/etc/crypttab" 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 path_dropbear_pid="/.dropbear.pid"
local dropbear_login_shell="/.cryptsetup_shell.sh" 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 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 local cryptdev cryptdev_orig crypttype cryptname cryptpass cryptoptions cryptopt cryptargs CSQUIET
# Load our options
sshcs_env_load
# sanity check: crypttab should be present # sanity check: crypttab should be present
[ ! -e "${etc_crypttab}" ] && return 0 [ ! -e "${etc_crypttab}" ] && return 0
@ -236,14 +257,6 @@ run_hook() {
umask 0022 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 # check encrypted devices to handle
cryptdev= cryptdev=
crypttype=luks crypttype=luks
@ -256,9 +269,17 @@ run_hook() {
sshcs_cryptpart_process sshcs_cryptpart_process
done < "${etc_crypttab}" done < "${etc_crypttab}"
if [ ! -e "${dropbear_cryptsetup_script}" ]; then if [ ! -e "${sshcs_cryptsetup_script}" ]; then
err "No encrypted device found! Skipping crypt remote unlocking." 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 sshcs_net_done
return 0 return 0
fi fi

View File

@ -31,7 +31,7 @@ sshcs_check_keys() {
build() { build() {
local etc_crypttab="/etc/crypttab" local etc_crypttab="/etc/crypttab"
local dropbear_authorized_keys="/etc/dropbear/initrd.authorized_keys" 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_key_types=( "dss" "rsa" "ecdsa" )
local dropbear_keyfile_prefix="/etc/dropbear/dropbear_" local dropbear_keyfile_prefix="/etc/dropbear/dropbear_"
local dropbear_keyfile_suffix="_host_key" local dropbear_keyfile_suffix="_host_key"
@ -71,12 +71,14 @@ build() {
add_binary "ip" add_binary "ip"
add_binary "/usr/lib/initcpio/ipconfig" "/sbin/ipconfig" add_binary "/usr/lib/initcpio/ipconfig" "/sbin/ipconfig"
# Our hook files
[ -e "${sshcs_env}" ] && add_file "${sshcs_env}"
# auth-related files # auth-related files
add_file "/lib/libnss_files.so" add_file "/lib/libnss_files.so"
# SSH-related files # SSH-related files
add_file "${dropbear_authorized_keys}" "/root/.ssh/authorized_keys" 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_rsa_host_key"
add_file "/etc/dropbear/dropbear_dss_host_key" add_file "/etc/dropbear/dropbear_dss_host_key"
add_file "/etc/dropbear/dropbear_ecdsa_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'. 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 LUKS encrypted devices to unlock are derived from '/etc/crypttab', which must
be present. 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): initrd shell):
* 'sshcs_opt_timeout_ipconfig': time (s) to configure IP
- default: 10 seconds
* 'sshcs_opt_listen': listening port (22 by default) * 'sshcs_opt_listen': listening port (22 by default)
* 'sshcs_opt_timeout_poweroff': time (s) to unlock devices before automatic * 'sshcs_opt_timeout_poweroff': time (s) to unlock devices before automatic
powering off powering off