13 Commits
0.2-1 ... 0.9-2

Author SHA1 Message Date
Julien Coloos
3449995d4a Use SHA256 checksums instead of MD5
v0.9-2
2021-11-12 19:25:06 +01:00
Julien Coloos
c3cafcf6cd Try to print network devices information when interface setup fails
Useful to check interfaces name and MAC address.

v0.9-1
2021-10-24 17:56:16 +02:00
Julien Coloos
b3e9382f08 Example to convert existing OpenSSH key to PEM format 2021-08-15 23:07:37 +02:00
Julien Coloos
8ebd239c7a Include 'libgcc_s.so.1' for proper LUKS v2 support
v0.8-1
2021-08-15 22:58:32 +02:00
Julien Coloos
bc04382857 Drop 'dsa' and add 'ed25519' private key support
Update README: dropbearconvert requires OpenSSH keys in PEM format.

Changed installation script to rely on variables, especially the list of
handled private key types, to that it automatically packages expected
private keys, instead of having to explicitely name/package them.
2020-07-14 16:22:54 +02:00
Julien Coloos
e47043f3a1 Drop '-m' option when calling dropbear
Latest ArchLinux versions does not handle it.
Boot fs is unlikely to have motd anyway.

v0.6-1
2018-03-13 22:20:27 +01:00
Julien Coloos
4c1a7741d6 README: don't forget to update ChangeLog when necessary 2018-03-13 22:17:19 +01:00
Julien Coloos
6167cbc9cd More details on installation and configuration
Mention dropbear SSH key generation (or conversion from OpenSSH).
Give example to setup IP with grub.
Some fixes/details.
2017-09-03 21:34:10 +02:00
Julien Coloos
a13fecf645 Add comment about keymap HOOK when using non-standard keyboard layout 2017-07-09 16:17:19 +02:00
Julien Coloos
d94d257cf6 Fix cryptsetup additional arguments handling
Quoting used in script prevented them ot be properly passed.
Also added a debug mode to print some more messages about ongoing actions.
2017-06-25 20:07:07 +02:00
Julien Coloos
e5ee05f382 Fixed TRIM option handling in /etc/crypttab
'discard' ('allow-discards' being the switch name to use in cryptsetup)

v0.4-1
2017-06-25 18:22:53 +02:00
Julien Coloos
cf6ccb2d23 Updated changelog 2015-11-22 19:05:58 +01:00
Julien Coloos
724d6a6bf0 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
2015-11-22 18:54:57 +01:00
6 changed files with 461 additions and 294 deletions

View File

@@ -1,19 +1,75 @@
2021-11-12 Julien Coloos <julien.coloos [at] gmail [dot] com>
* v0.10-1
Option to use login shell instead of cryptsetup script
Re-enable Wake-on-LAN on network device
2021-11-12 Julien Coloos <julien.coloos [at] gmail [dot] com>
* v0.9-2
Use SHA256 checksums instead of MD5
2021-10-24 Julien Coloos <julien.coloos [at] gmail [dot] com>
* v0.9-1
Try to print network devices information when interface setup fails
2021-08-15 Julien Coloos <julien.coloos [at] gmail [dot] com>
* v0.8-1
Include 'libgcc_s.so.1' which is necessary for (at least) proper LUKS v2 handling
2020-07-14 Julien Coloos <julien.coloos [at] gmail [dot] com>
* v0.7-1
Dropped 'dsa' private key support; added 'ed25519' private key support
2018-03-13 Julien Coloos <julien.coloos [at] gmail [dot] com>
* v0.6-1
Dropped '-m' option when calling dropbear (latest ArchLinux version does not handle it)
2017-06-25 Julien Coloos <julien.coloos [at] gmail [dot] com>
* v0.5-1
Fixed cryptsetup additional arguments handling: were not properly passed
2017-06-25 Julien Coloos <julien.coloos [at] gmail [dot] com>
* v0.4-1
Fixed TRIM option handling in /etc/crypttab: 'discard' ('allow-discards' being the switch name to use in cryptsetup)
2015-11-22 Julien Coloos <julien.coloos [at] gmail [dot] com>
* v0.3-1
Added configurable timeout for ipconfig
Moved configuration file from /etc/dropbear/initrd.env to /etc/initcpio/sshcs_env
2014-05-20 Julien Coloos <julien.coloos [at] gmail [dot] com>
* v0.2-1
Removed unnecessary dependency: psmisc
Added configurable timeout to unlock devices before automatic poweroff
* v0.2-1
Removed unnecessary dependency: psmisc
Added configurable timeout to unlock devices before automatic poweroff
2014-05-19 Julien Coloos <julien.coloos [at] gmail [dot] com>
* v0.1-1
* v0.1-1
* Code adapted from dropbear_initrd_encrypt (https://aur.archlinux.org/packages/dropbear_initrd_encrypt/)
Reworked code
Dropped non-LUKS support
Rely on /etc/crypttab
Handle multiple devices to unlock
Merged dropbear and encryptssh hooks
Better resources cleanup
* Code adapted from dropbear_initrd_encrypt (https://aur.archlinux.org/packages/dropbear_initrd_encrypt/)
Reworked code
Dropped non-LUKS support
Rely on /etc/crypttab
Handle multiple devices to unlock
Merged dropbear and encryptssh hooks
Better resources cleanup

View File

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

View File

@@ -1,29 +1,69 @@
Personal ArchLinux package combining dropbear and cryptsetup in initrd for unlocking LUKS-encrypted devices either locally (boot console) or remotely over SSH.
The code was reworked from [dropbear_initrd_encrypt](https://aur.archlinux.org/packages/dropbear_initrd_encrypt/).
Personal ArchLinux package combining dropbear and cryptsetup in initrd for unlocking LUKS-encrypted devices either locally (boot console) or remotely over SSH.
The code was reworked from legacy dropbear_initrd_encrypt AUR package.
## Installation
After cloning the repo, installation is done as for an AUR package.
After cloning the repo, installation is done as for an AUR package, e.g.:
makepkg -sri
## Dropbear
SSH server key need to be generated for `dropbear`.
Either a new key can be generated with `dropbearkey`, e.g.:
dropbearkey -t ecdsa -f /etc/dropbear/dropbear_ecdsa_host_key
Or an existing OpenSSH key can be converted with `dropbearconvert` (useful so that the server fingerprint is the same with both), e.g.:
dropbearconvert openssh dropbear /etc/ssh/ssh_host_ecdsa_key /etc/dropbear/dropbear_ecdsa_host_key
Notes:
* `rsa` and `ed25519` types are also handled
* OpenSSH keys must be in `PEM` format for `dropbearconvert` to properly work
If necessary an existing key file can be converted to `PEM` format using `ssh-keygen`:
ssh-keygen -A -p -m PEM -f /etc/ssh/ssh_host_ecdsa_key
## Configuration
As explained upon installation, the following things need to be done:
* add the SSH public key to `/etc/dropbear/initrd.authorized_keys`
* add the `ip=` kernel command parameter to the bootloader configuration (see https://wiki.archlinux.org/index.php/Mkinitcpio#Using_net)
* in the `HOOKS` section of `/etc/mkinitcpio.conf`, add `ssh-cryptsetup` before `filesystems`; then rebuild the initramfs: `mkinitcpio -p linux`
* add the authorized SSH public key to `/etc/dropbear/initrd.authorized_keys`
* add the `ip=` kernel command parameter to the bootloader configuration (see https://wiki.archlinux.org/index.php/Mkinitcpio#Using_net)
- e.g. with `grub`: add `ip=:::::eth0:dhcp` to `GRUB_CMDLINE_LINUX_DEFAULT` in `/etc/default/grub`, and re-generate the configuration with `grub-mkconfig -o /boot/grub/grub.cfg`
- also see https://git.kernel.org/pub/scm/libs/klibc/klibc.git/tree/usr/kinit/ipconfig/README.ipconfig
* in the `HOOKS` section of `/etc/mkinitcpio.conf`, add `ssh-cryptsetup` before `filesystems`; then rebuild the initramfs: `mkinitcpio -p linux`
- when using a non-standard keyboard layout, it is also useful to add the `keymap` hook before `ssh-cryptsetup`, and also move `keyboard` before `keymap`
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):
* `sshcs_opt_listen`: SSH listening port
- default: 22
* `sshcs_opt_timeout_poweroff`: time (in seconds) to unlock devices before automatic powering off
- default (and minimum value): 2 minutes
- negative value to deactivate
Some options can be set in `/etc/initcpio/sshcs_env` (file is sourced in initrd shell):
* `sshcs_opt_debug`: whether to be more verbose about ongoing actions
- default: 0
- any non-zero value to enable
* `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
- default (and minimum value): 2 minutes
- negative value to deactivate
For example:
sshcs_opt_timeout_ipconfig=30
sshcs_opt_listen=2222
sshcs_opt_timeout_poweroff=-1
## Building notes
1. Modify the sources (features in `src`, and/or package building files)
2. If `src` was modified
* archive the `src` folder in `$pkgname-$pkgver.tar.xz` file; e.g.: `tar -cJf initrd-ssh-cryptsetup-0.9.tar.xz src`
* upload the archive on the online repository (pointed by `PKGBUILD`)
3. Update ChangeLog
4. Update `PKGBUILD`
* bump `pkgver` if `src` was modified, or `pkgrel` if building files were modified
* refresh `sha256sums` with `updpkgsums` if necessary
- or manually, based on `sha256sum initrd-ssh-cryptsetup-*.tar.xz initrd-ssh-cryptsetup.install` output
5. Delete generated archive file if any

View File

@@ -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 <<EOF
Moved legacy file ${sshcs_env_old} to new path ${sshcs_env}"
EOF
}
[ -d "${etc_dropbear}" ] || mkdir -p "${etc_dropbear}"
[ -e "${dropbear_authorized_keys}" ] || touch "${dropbear_authorized_keys}"
chmod 600 "${dropbear_authorized_keys}"

View File

@@ -1,270 +1,318 @@
#!/usr/bin/ash
dbg () {
[ ${sshcs_opt_debug} != 0 ] && echo "$@"
}
sshcs_env_load() {
local debug_default=0
local timeout_ipconfig_default=10
local timeout_poweroff_min=120
local use_shell_default=0
[ -e "${sshcs_env}" ] && . "${sshcs_env}"
[ -z "${sshcs_opt_debug}" ] && sshcs_opt_debug=${debug_default}
[ -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}
[ -z "${sshcs_opt_use_shell}" ] && sshcs_opt_use_shell=${use_shell_default}
[ ${sshcs_opt_timeout_poweroff} -ge 0 ] && [ ${sshcs_opt_timeout_poweroff} -lt ${timeout_poweroff_min} ] && sshcs_opt_timeout_poweroff=${timeout_poweroff_min}
}
sshcs_net_start() {
# we must have an 'ip' setting, and a device in it
[ -z "${ip}" ] && [ -n "${nfsaddrs}" ] && ip="${nfsaddrs}"
[ -z "${ip}" ] && return 1
# we must have an 'ip' setting, and a device in it
[ -z "${ip}" ] && [ -n "${nfsaddrs}" ] && ip="${nfsaddrs}"
[ -z "${ip}" ] && {
dbg "No ip setting to setup network"
return 1
}
net_device=$(echo ${ip} | cut -d: -f6)
[ -z "${net_device}" ] && return 1
net_device=$(echo ${ip} | cut -d: -f6)
[ -z "${net_device}" ] && {
dbg "No network device to setup"
return 1
}
# Setup network and save some values
# Note: some useful redirection means ('< <(...)' and '<<< "$(...)"') are
# not supported in the available shell. So we have to write code in a
# temporary file and 'source' it since '... | while read ...' spawns a
# subshell from which outer variables cannot be altered.
: > "${net_env}"
ipconfig "ip=${ip}" | while read line; do
[ "${line#"IP-Config:"}" != "${line}" ] && continue
# Setup network and save some values
# Note: some useful redirection means ('< <(...)' and '<<< "$(...)"') are
# not supported in the available shell. So we have to write code in a
# temporary file and 'source' it since '... | while read ...' spawns a
# subshell from which outer variables cannot be altered.
: > "${net_env}"
line="$(echo "${line}" | sed -e 's/ :/:/g;s/: /=/g')"
echo ""
echo "Configuring IP (timeout = ${sshcs_opt_timeout_ipconfig}s) ..."
# ipconfig manual: https://git.kernel.org/pub/scm/libs/klibc/klibc.git/tree/usr/kinit/ipconfig/README.ipconfig
ipconfig_out=$(ipconfig -t "${sshcs_opt_timeout_ipconfig}" "ip=${ip}")
if [ $? -ne 0 ]; then
err "IP configuration timeout!"
echo "Devices probing:"
ipconfig -n -t 5 -c none all
return 1
fi
for iparg in ${line}; do
case "${iparg}" in
address=*|netmask=*|gateway=*|dns0=*|dns1=*)
echo "net_${iparg}" >> "${net_env}"
;;
esac
done
echo -n "${ipconfig_out}" | while read line; do
[ "${line#"IP-Config:"}" != "${line}" ] && continue
line="$(echo "${line}" | sed -e 's/ :/:/g;s/: /=/g')"
for iparg in ${line}; do
case "${iparg}" in
address=*|netmask=*|gateway=*|dns0=*|dns1=*)
echo "net_${iparg}" >> "${net_env}"
;;
esac
done
done
. "${net_env}"
rm -f "${net_env}"
. "${net_env}"
rm -f "${net_env}"
echo "IP-Config: device=${net_device} ip=${net_address}/${net_netmask} gw=${net_gateway} dns0=${net_dns0} dns1=${net_dns1}"
echo "IP-Config: device=${net_device} ip=${net_address}/${net_netmask} gw=${net_gateway} dns0=${net_dns0} dns1=${net_dns1}"
[ -n "${net_address}" ]
[ -n "${net_address}" ]
}
sshcs_net_done() {
# we are done with the network
if [ -n "${net_device}" ]; then
dbg "Setting network device=${net_device} down"
ip addr flush dev "${net_device}"
ip link set dev "${net_device}" down
fi
}
sshcs_trapped_timeout() {
err "Timeout reached! Powering off."
poweroff -f
exit
err "Timeout reached! Powering off."
poweroff -f
exit
}
sshcs_trap_timeout() {
local pid_init=$$
local pid_init=$$
if [ ${sshcs_opt_timeout_poweroff} -gt 0 ]; then
echo ""
echo "WARNING! Automatic poweroff will be triggered in ${sshcs_opt_timeout_poweroff}s"
echo "To deactivate, please unlock devices"
echo ""
trap sshcs_trapped_timeout SIGALRM
(
sleep ${sshcs_opt_timeout_poweroff}
kill -SIGALRM ${pid_init}
# Signal is not processed if cryptsetup is waiting for the password
killall cryptsetup > /dev/null 2>&1
) &
pid_timeout=$!
fi
if [ ${sshcs_opt_timeout_poweroff} -gt 0 ]; then
echo ""
echo "WARNING! Automatic poweroff will be triggered in ${sshcs_opt_timeout_poweroff}s"
echo "To deactivate, please unlock devices"
echo ""
trap sshcs_trapped_timeout SIGALRM
(
sleep ${sshcs_opt_timeout_poweroff}
kill -SIGALRM ${pid_init}
# Signal is not processed if cryptsetup is waiting for the password
killall cryptsetup > /dev/null 2>&1
) &
pid_timeout=$!
fi
}
sshcs_untrap_timeout() {
[ -z "${pid_timeout}" ] && return 0
kill ${pid_timeout}
trap - SIGALRM
msg "Timeout cleared."
[ -z "${pid_timeout}" ] && return 0
kill ${pid_timeout}
trap - SIGALRM
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=
local pid_timeout=
local dev_pts_mounted=0
local listen=
# ensure /dev/pts is present
if [ ! -d "/dev/pts" ]; then
mkdir -p "/dev/pts"
mount -t devpts devpts "/dev/pts"
dev_pts_mounted=1
fi
# ensure /dev/pts is present
if [ ! -d "/dev/pts" ]; then
mkdir -p "/dev/pts"
mount -t devpts devpts "/dev/pts"
dev_pts_mounted=1
fi
# /etc/passwd file for the root user
echo "root:x:0:0:root:/root:${dropbear_login_shell}" > "/etc/passwd"
echo "${dropbear_login_shell}" > "/etc/shells"
# /etc/passwd file for the root user
if [ ${sshcs_opt_use_shell} -eq 0 ]; then
echo "root:x:0:0:root:/root:${dropbear_cryptsetup_shell}" > "/etc/passwd"
echo "${dropbear_cryptsetup_shell}" > "/etc/shells"
else
echo "root:x:0:0:root:/root:/usr/bin/ash" > "/etc/passwd"
fi
# root login script
cat <<EOF > "${dropbear_login_shell}"
# root login script
cat <<EOF > "${dropbear_cryptsetup_shell}"
#!/usr/bin/ash
. "/init_functions"
if [ ! -f "${dropbear_cryptsetup_script}" ]; then
err "No cryptsetup script present! Please retry."
exit 0
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}"
CSQUIET=
. "${sshcs_cryptsetup_script}"
echo ""
echo "cryptsetup succeeded! Boot sequence should go on."
echo "Please wait and retry for standard SSH service."
echo ""
echo "cryptsetup succeeded! Boot sequence should go on."
echo "Please wait and retry for standard SSH service."
else
err "Device resources missing! Please retry."
err "Device resources missing! Please retry."
fi
echo ""
EOF
chmod a+x "${dropbear_login_shell}"
chmod a+x "${dropbear_cryptsetup_shell}"
[ ! -d "/var/log" ] && mkdir -p "/var/log"
touch "/var/log/lastlog"
[ ! -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 -Esgjk -P "${path_dropbear_pid}" ${sshcs_opt_listen}
# Actual unlocking
sshcs_unlock
msg "Starting dropbear ..."
dropbear -Emsgjk -P "${path_dropbear_pid}" ${sshcs_opt_listen}
# cleanup dropbear
if [ -f "${path_dropbear_pid}" ]; then
msg "Stopping dropbear ..."
kill $(cat "${path_dropbear_pid}")
rm -f "${path_dropbear_pid}"
fi
rm -f "${sshcs_cryptsetup_script}" "${dropbear_cryptsetup_shell}" "/etc/passwd" "/etc/shells" "/var/log/lastlog"
sshcs_trap_timeout
# actual script (shared with SSH login) unlocking encrypted devices
. "${dropbear_cryptsetup_script}"
sshcs_untrap_timeout
# cleanup dropbear
if [ -f "${path_dropbear_pid}" ]; then
msg "Stopping dropbear ..."
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"
# cleanup /dev/pts if necessary
if [ ${dev_pts_mounted} -ne 0 ]; then
umount "/dev/pts"
rm -R "/dev/pts"
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
# cleanup /dev/pts if necessary
if [ ${dev_pts_mounted} -ne 0 ]; then
umount "/dev/pts"
rm -R "/dev/pts"
fi
}
sshcs_cryptpart_process() {
# ensure there is a device (handle 'UUID=' format)
[ -z "${cryptdev}" ] && return 0
[ "${cryptdev#UUID=}" != "${cryptdev}" ] && cryptdev="/dev/disk/by-uuid/${cryptdev#UUID=}"
# ensure there is a device (handle 'UUID=' format)
[ -z "${cryptdev}" ] && return 0
[ "${cryptdev#UUID=}" != "${cryptdev}" ] && cryptdev="/dev/disk/by-uuid/${cryptdev#UUID=}"
# get crypt options
cryptargs=
for cryptopt in ${cryptoptions//,/ }; do
case ${cryptopt} in
allow-discards)
cryptargs="${cryptargs} --allow-discards"
;;
# get crypt options
cryptargs=
for cryptopt in ${cryptoptions//,/ }; do
case ${cryptopt} in
discard)
cryptargs="${cryptargs} --allow-discards"
;;
luks)
;;
luks)
;;
*)
echo "Device ${cryptdev} encryption option '${cryptopt}' not known, ignoring."
;;
esac
done
*)
echo "Device ${cryptdev} encryption option '${cryptopt}' not known, ignoring."
;;
esac
done
# ensure device is encrypted and handled
cryptdev_orig=${cryptdev}
if cryptdev=$(resolve_device "${cryptdev_orig}" ${rootdelay}); then
if cryptsetup isLuks "${cryptdev}" >/dev/null 2>&1; then
# ensure device is encrypted and handled
cryptdev_orig=${cryptdev}
if cryptdev=$(resolve_device "${cryptdev_orig}" ${rootdelay}); then
if cryptsetup isLuks "${cryptdev}" >/dev/null 2>&1; then
dbg "Adding crypt device=${cryptdev} type=${crypttype} name=${cryptname} args=<${cryptargs}> in setup script"
# update script used to unlock device either in console or SSH
[ -s "${dropbear_cryptsetup_script}" ] || cat <<EOF > "${dropbear_cryptsetup_script}"
# update script used to unlock device either in console or SSH
[ -s "${sshcs_cryptsetup_script}" ] || cat <<EOF > "${sshcs_cryptsetup_script}"
cycle_or_retry() {
local res
local res
read -n 1 -s -t 5 -p "Whithin 5s press 'P' to poweroff, 'R' to reboot or any other key to retry. " res
echo ""
if [ "\${res}" = "P" ]; then
poweroff -f
elif [ "\${res}" = "R" ]; then
reboot -f
fi
read -n 1 -s -t 5 -p "Whithin 5s press 'P' to poweroff, 'R' to reboot or any other key to retry. " res
echo ""
if [ "\${res}" = "P" ]; then
poweroff -f
elif [ "\${res}" = "R" ]; then
reboot -f
fi
}
EOF
cat <<EOF >> "${dropbear_cryptsetup_script}"
cat <<EOF >> "${sshcs_cryptsetup_script}"
# loop until device is available
while [ ! -e "/dev/mapper/${cryptname}" ]; do
if cryptsetup open --type "${crypttype}" "${cryptdev}" "${cryptname}" "${cryptargs}" "\${CSQUIET}"; then
if poll_device "/dev/mapper/${cryptname}" ${rootdelay}; then
killall cryptsetup > /dev/null 2>&1
break
fi
err "Device still not mapped! Please wait or retry."
elif [ ! -e "/dev/mapper/${cryptname}" ]; then
err "cryptsetup failed! Please retry."
else
break
if cryptsetup open --type "${crypttype}" "${cryptdev}" "${cryptname}" ${cryptargs} "\${CSQUIET}"; then
if poll_device "/dev/mapper/${cryptname}" ${rootdelay}; then
killall cryptsetup > /dev/null 2>&1
break
fi
err "Device still not mapped! Please wait or retry."
elif [ ! -e "/dev/mapper/${cryptname}" ]; then
err "cryptsetup failed! Please retry."
else
break
fi
cycle_or_retry
cycle_or_retry
done
EOF
else
err "Failed to manage encrypted device ${cryptdev_orig}: not a LUKS volume."
fi
else
err "Failed to manage encrypted device ${cryptdev_orig}: not a LUKS volume."
fi
fi
}
run_hook() {
local etc_crypttab="/etc/crypttab"
local dropbear_env="/etc/dropbear/initrd.env"
local path_dropbear_pid="/.dropbear.pid"
local dropbear_login_shell="/.cryptsetup_shell.sh"
local dropbear_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 cryptdev cryptdev_orig crypttype cryptname cryptpass cryptoptions cryptopt cryptargs CSQUIET
local etc_crypttab="/etc/crypttab"
local sshcs_env="/etc/initcpio/sshcs_env"
local path_dropbear_pid="/.dropbear.pid"
local dropbear_cryptsetup_shell="/.cryptsetup_shell.sh"
local sshcs_cryptsetup_script="/.cryptsetup_script.sh"
local net_env="/.net_env.sh"
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
# sanity check: crypttab should be present
[ ! -e "${etc_crypttab}" ] && return 0
# Load our options
sshcs_env_load
modprobe -a -q dm-crypt >/dev/null 2>&1
[ "${quiet}" = "y" ] && CSQUIET=">/dev/null"
# sanity check: crypttab should be present
[ ! -e "${etc_crypttab}" ] && {
dbg "No crypttab configuration to process"
return 0
}
umask 0022
modprobe -a -q dm-crypt >/dev/null 2>&1
[ "${quiet}" = "y" ] && CSQUIET=">/dev/null"
# 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
umask 0022
# check encrypted devices to handle
cryptdev=
crypttype=luks
while read cryptname cryptdev cryptpass cryptoptions; do
# skip comment lines
[ "${cryptname:0:1}" = "#" ] && continue
# skip devices with given password
[ -n "${cryptpass}" ] && [ "${cryptpass}" != "none" ] && [ "${cryptpass}" != "-" ] && continue
# check encrypted devices to handle
cryptdev=
crypttype=luks
while read cryptname cryptdev cryptpass cryptoptions; do
# skip comment lines
[ "${cryptname:0:1}" = "#" ] && continue
# skip devices with given password
[ -n "${cryptpass}" ] && [ "${cryptpass}" != "none" ] && [ "${cryptpass}" != "-" ] && continue
sshcs_cryptpart_process
done < "${etc_crypttab}"
sshcs_cryptpart_process
done < "${etc_crypttab}"
if [ ! -e "${dropbear_cryptsetup_script}" ]; then
err "No encrypted device found! Skipping crypt remote unlocking."
# don't forget to stop the network
sshcs_net_done
return 0
fi
if [ ! -e "${sshcs_cryptsetup_script}" ]; then
err "No encrypted device found! Skipping crypt remote unlocking."
return 0
fi
# time to unlock (through console or dropbear)
sshcs_dropbear_unlock
# stop the network before going on in boot sequence
# 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
# time to unlock (through console or dropbear)
sshcs_dropbear_unlock
# stop the network before going on in boot sequence
sshcs_net_done
}

View File

@@ -1,99 +1,110 @@
#!/bin/bash
sshcs_check_nonempty() {
local filepath="$1"
local filepath="$1"
[ -e "${filepath}" ] && grep -q -v '^\s*\(#\|$\)' "${filepath}"
[ -e "${filepath}" ] && grep -q -v '^\s*\(#\|$\)' "${filepath}"
}
sshcs_check_keys() {
local dropbear_keyfile
local openssh_keyfile
local fingerprint
local dropbear_keyfile
local openssh_keyfile
local fingerprint
for keytype in "${dropbear_key_types[@]}"; do
dropbear_keyfile=${dropbear_keyfile_prefix}${keytype}${dropbear_keyfile_suffix}
openssh_keyfile=${openssh_keyfile_prefix}${keytype}${openssh_keyfile_suffix}
for keytype in "${dropbear_key_types[@]}"; do
dropbear_keyfile=${dropbear_keyfile_prefix}${keytype}${dropbear_keyfile_suffix}
openssh_keyfile=${openssh_keyfile_prefix}${keytype}${openssh_keyfile_suffix}
# Prefer OpenSSH keys, or generate missing ones
if [ -e "${openssh_keyfile}" ]; then
#echo "Copying OpenSSH ${keytype} host key for dropbear ..."
dropbearconvert openssh dropbear "${openssh_keyfile}" "${dropbear_keyfile}" > /dev/null 2>&1
elif [ ! -e "${dropbear_keyfile}" ]; then
#echo "Generating ${keytype} host key for dropbear ..."
dropbearkey -t "${keytype}" -f "${dropbear_keyfile}" > /dev/null 2>&1
fi
fingerprint=$(dropbearkey -y -f "${dropbear_keyfile}" | sed -n '/^Fingerprint:/ {s/Fingerprint: *//; p}')
echo "$(basename "${dropbear_keyfile}") : ${fingerprint}"
done
# Prefer OpenSSH keys, or generate missing ones
if [ -e "${openssh_keyfile}" ]; then
#echo "Copying OpenSSH ${keytype} host key for dropbear ..."
dropbearconvert openssh dropbear "${openssh_keyfile}" "${dropbear_keyfile}" > /dev/null 2>&1
elif [ ! -e "${dropbear_keyfile}" ]; then
#echo "Generating ${keytype} host key for dropbear ..."
dropbearkey -t "${keytype}" -f "${dropbear_keyfile}" > /dev/null 2>&1
fi
fingerprint=$(dropbearkey -y -f "${dropbear_keyfile}" | sed -n '/^Fingerprint:/ {s/Fingerprint: *//; p}')
echo "$(basename "${dropbear_keyfile}") : ${fingerprint}"
done
}
build() {
local etc_crypttab="/etc/crypttab"
local dropbear_authorized_keys="/etc/dropbear/initrd.authorized_keys"
local dropbear_env="/etc/dropbear/initrd.env"
local dropbear_key_types=( "dss" "rsa" "ecdsa" )
local dropbear_keyfile_prefix="/etc/dropbear/dropbear_"
local dropbear_keyfile_suffix="_host_key"
local openssh_keyfile_prefix="/etc/ssh/ssh_host_"
local openssh_keyfile_suffix="_key"
local etc_crypttab="/etc/crypttab"
local dropbear_authorized_keys="/etc/dropbear/initrd.authorized_keys"
local sshcs_env="/etc/initcpio/sshcs_env"
local dropbear_key_types=( "rsa" "ecdsa" "ed25519" )
local dropbear_keyfile_prefix="/etc/dropbear/dropbear_"
local dropbear_keyfile_suffix="_host_key"
local openssh_keyfile_prefix="/etc/ssh/ssh_host_"
local openssh_keyfile_suffix="_key"
# Check we are needed
if ! sshcs_check_nonempty "${dropbear_authorized_keys}"; then
echo "There is no root key(s) in ${dropbear_authorized_keys}. Skipping."
return 0
fi
if ! sshcs_check_nonempty "${etc_crypttab}"; then
echo "There is no device in ${etc_crypttab}. Skipping."
return 0
fi
# Check we are needed
if ! sshcs_check_nonempty "${dropbear_authorized_keys}"; then
echo "There is no root key(s) in ${dropbear_authorized_keys}. Skipping."
return 0
fi
if ! sshcs_check_nonempty "${etc_crypttab}"; then
echo "There is no device in ${etc_crypttab}. Skipping."
return 0
fi
umask 0022
umask 0022
sshcs_check_keys
sshcs_check_keys
add_checked_modules "/drivers/net/"
add_module dm-crypt
# Note: crypto modules are necessary
if [ -n "${CRYPTO_MODULES}" ]; then
local mod
for mod in ${CRYPTO_MODULES}; do
add_module "${mod}"
done
else
add_all_modules "/crypto/"
fi
add_checked_modules "/drivers/net/"
# Note: parts of this script (modules/binaries added) are the same than the
# 'encrypt' install script (/usr/lib/initcpio/install/encrypt) which is the
# nominal one to deal with encrypted volumes at boot time.
add_module dm-crypt
# Note: crypto modules are necessary
if [ -n "${CRYPTO_MODULES}" ]; then
local mod
for mod in ${CRYPTO_MODULES}; do
add_module "${mod}"
done
else
add_all_modules "/crypto/"
fi
# Note: dmsetup is necessary for device mapper features
add_binary "cryptsetup"
add_binary "dmsetup"
add_binary "dropbear"
add_binary "ip"
add_binary "/usr/lib/initcpio/ipconfig" "/sbin/ipconfig"
# Note: dmsetup is necessary for device mapper features
add_binary "cryptsetup"
add_binary "dmsetup"
add_binary "dropbear"
add_binary "ip"
add_binary "/usr/lib/initcpio/ipconfig" "/bin/ipconfig"
add_binary "ethtool"
# auth-related files
add_file "/lib/libnss_files.so"
# Our hook files
[ -e "${sshcs_env}" ] && add_file "${sshcs_env}"
# 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"
# auth-related files
add_file "/lib/libnss_files.so"
# cryptsetup-related files
add_file "${etc_crypttab}"
add_file "/usr/lib/udev/rules.d/10-dm.rules"
add_file "/usr/lib/udev/rules.d/13-dm-disk.rules"
add_file "/usr/lib/udev/rules.d/95-dm-notify.rules"
add_file "/usr/lib/initcpio/udev/11-dm-initramfs.rules" "/usr/lib/udev/rules.d/11-dm-initramfs.rules"
# SSH-related files
add_file "${dropbear_authorized_keys}" "/root/.ssh/authorized_keys"
for keytype in "${dropbear_key_types[@]}"; do
add_file "${dropbear_keyfile_prefix}${keytype}${dropbear_keyfile_suffix}"
done
# cryptsetup-related files
add_file "${etc_crypttab}"
add_file "/usr/lib/udev/rules.d/10-dm.rules"
add_file "/usr/lib/udev/rules.d/13-dm-disk.rules"
add_file "/usr/lib/udev/rules.d/95-dm-notify.rules"
add_file "/usr/lib/initcpio/udev/11-dm-initramfs.rules" "/usr/lib/udev/rules.d/11-dm-initramfs.rules"
add_runscript
# At least with LUKS v2 volumes, cryptsetup calls pthread_cancel(), which
# dlopen()s libgcc_s.so.1.
# See the nominal 'encrypt' module, and similar/related bug reports (e.g.
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=950254).
add_binary "/usr/lib/libgcc_s.so.1"
add_runscript
}
help() {
cat <<EOF
cat <<EOF
This hook allows for LUKS encrypted devices to be unlocked either locally
(boot console) or remotely over SSH.
@@ -101,17 +112,20 @@ 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
- default (and minimum value): 2 minutes
- negative value to deactivate
Each SSH server key ('dropbear_rsa_host_key', 'dropbear_dss_host_key' and
'dropbear_ecdsa_host_key' in '/etc/dropbear' folder) is imported from OpenSSH
Each SSH server key ('dropbear_rsa_host_key', 'dropbear_ecdsa_host_key' and
'dropbear_ed25519_host_key' in '/etc/dropbear' folder) is imported from OpenSSH
if present or generated if missing. Fingerprints are displayed upon building
the initramfs image.
EOF
}