Compare commits

...

17 Commits

Author SHA1 Message Date
Julien Coloos 22da78cdef v1.1-1 2022-03-24 21:58:20 +01:00
Julien Coloos d34b39b77f Refactored install script
Re-arrange and add comments to more easily spot code coming from other
hooks.
2022-03-24 21:52:03 +01:00
Julien Coloos 8f92d149eb Update help message after install
Show up-to-date options details.
2022-03-24 21:49:09 +01:00
Julien Coloos f20941d376 Options to re-enable WOL and start a full shell
Adding ethtool - to allows chaning WOL settings - does not add much more
dependencies compared to the core ones (network, dropbear, cryptsetup).

Refactor script for easier maintenance.

v1.0-1
2021-11-13 21:02:49 +01:00
Julien Coloos a2924457d3 Use SHA256 checksums instead of MD5 2021-11-13 17:00:58 +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
7 changed files with 756 additions and 335 deletions

View File

@ -1,19 +1,95 @@
2022-03-24 Julien Coloos <julien.coloos [at] gmail [dot] com>
* v1.1-1
Refactored install script to more easily spot code coming from other
nominal hooks.
Updated install script message with latest available options.
Removed dependency to '/lib/libnss_files.so', as it does not exist and
should not be needed anymore.
Prevents unwanted warning when building initcpio
==> ERROR: file not found: `/lib/libnss_files.so'
See: https://bugs.archlinux.org/task/73702
2021-11-13 Julien Coloos <julien.coloos [at] gmail [dot] com>
* v1.0-1
Option to use login shell instead of cryptsetup unlocking script.
Option to 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> 2014-05-20 Julien Coloos <julien.coloos [at] gmail [dot] com>
* v0.2-1 * v0.2-1
Removed unnecessary dependency: psmisc Removed unnecessary dependency: psmisc.
Added configurable timeout to unlock devices before automatic poweroff Added configurable timeout to unlock devices before automatic poweroff.
2014-05-19 Julien Coloos <julien.coloos [at] gmail [dot] com> 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/) Code adapted from dropbear_initrd_encrypt.
Reworked code See: https://aur.archlinux.org/packages/dropbear_initrd_encrypt/
Dropped non-LUKS support
Rely on /etc/crypttab
Handle multiple devices to unlock
Merged dropbear and encryptssh hooks
Better resources cleanup
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,20 +1,21 @@
# 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=1.1
pkgrel=1 pkgrel=1
pkgdesc="Allows for LUKS-encrypted devices to be unlocked remotely over SSH" pkgdesc="Allows to remotely unlock LUKS-encrypted devices over SSH"
arch=('any') arch=('any')
url="https://github.com/suiryc/archlinux-$pkgname" url="https://github.com/suiryc/archlinux-$pkgname"
license=('GPL3') license=('GPL3')
depends=('dropbear' 'cryptsetup' 'mkinitcpio-nfs-utils' 'iproute2') depends=('dropbear' 'cryptsetup' 'mkinitcpio-nfs-utils' 'iproute2' 'ethtool')
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' sha256sums=('33295d11216cb96a5b30f035add123d136fac38decd393d677f1c02b9ad22379'
'a703663472bbd50882a11f6b2cfccbf0') 'b84978b3c2ef32208c2b104ee2d3ce8aaec26da0bd4e9e1c83942f373bbf6285')
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"
install -Dm644 "$srcdir/src/hooks/ssh-cryptsetup" "$pkgdir/usr/lib/initcpio/hooks/ssh-cryptsetup" install -Dm644 "$srcdir/src/hooks/ssh-cryptsetup" "$pkgdir/usr/lib/initcpio/hooks/ssh-cryptsetup"
install -Dm644 "$srcdir/src/hooks/ssh-cryptsetup-tools" "$pkgdir/usr/lib/initcpio/hooks/ssh-cryptsetup-tools"
} }

View File

@ -1,29 +1,79 @@
Personal ArchLinux package combining dropbear and cryptsetup in initrd for unlocking LUKS-encrypted devices either locally (boot console) or remotely over SSH. Personal ArchLinux package combining dropbear and cryptsetup in initramfs 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/). The code was reworked from legacy dropbear_initrd_encrypt AUR package.
## Installation ## 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 ## Configuration
As explained upon installation, the following things need to be done: As explained upon installation, the following things need to be done:
* add the SSH public key to `/etc/dropbear/initrd.authorized_keys` * 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) * 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` * 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`. 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 initramfs shell):
* `sshcs_opt_debug`: whether to be more verbose about ongoing actions
- default: `0`
- any non-zero value to enable
* `sshcs_opt_net_wol`: Wake-on-LAN option to set on network device
- default: `g` (MagicPacket™)
- usually WOL is disabled once in initramfs shell
- set empty to not change network device WOL setting
* `sshcs_opt_timeout_ipconfig`: time (in seconds) to configure IP
- default: `10`
* `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
- default (and minimum value): 2 minutes - default (and minimum value): `120` (2 minutes)
- negative value to deactivate - negative value to deactivate
* `sshcs_opt_use_shell`: whether to start a full `ash` shell
- default: `0`
- `1` to enable
- when disabled (the default), a script to unlock devices is executed instead
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
sshcs_opt_use_shell=1
## Building notes
1. Modify the sources (features in `src`, and/or package building files)
2. If `src` was modified
* bump `pkgver` in `PKGBUILD`
* archive the `src` folder in `$pkgname-$pkgver.tar.xz` file; e.g.: `tar -cJf initrd-ssh-cryptsetup-$(grep "^pkgver=" PKGBUILD | cut -d'=' -f2).tar.xz src`
* upload the archive on the online repository (pointed by `PKGBUILD`)
3. Update ChangeLog
4. Update `PKGBUILD`
* bump `pkgrel` if only 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 #!/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,12 +1,27 @@
#!/usr/bin/ash #!/usr/bin/ash
. "/usr/local/bin/ssh-cryptsetup-tools"
sshcs_net_start() { sshcs_net_start() {
local iparg net_address ipconfig_out net_netmask net_gateway net_dns0 net_dns1
# 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}"
[ -z "${ip}" ] && return 1 [ -z "${ip}" ] && {
dbg "No ip setting to setup network"
return 1
}
net_device=$(echo ${ip} | cut -d: -f6) net_device=$(echo ${ip} | cut -d: -f6)
[ -z "${net_device}" ] && return 1 [ -z "${net_device}" ] && {
dbg "No network device to setup"
return 1
}
if [ "${sshcs_opt_net_wol:-d}" != "d" ]; then
dbg "Setting network device=${net_device} wol=${sshcs_opt_net_wol}"
ethtool -s "${net_device}" wol "${sshcs_opt_net_wol}"
fi
# Setup network and save some values # Setup network and save some values
# Note: some useful redirection means ('< <(...)' and '<<< "$(...)"') are # Note: some useful redirection means ('< <(...)' and '<<< "$(...)"') are
@ -14,7 +29,19 @@ 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 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
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 +63,15 @@ sshcs_net_start() {
[ -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() { sshcs_trapped_timeout() {
err "Timeout reached! Powering off." err "Timeout reached! Powering off."
poweroff -f poweroff -f
@ -49,7 +85,6 @@ sshcs_trap_timeout() {
echo "" echo ""
echo "WARNING! Automatic poweroff will be triggered in ${sshcs_opt_timeout_poweroff}s" echo "WARNING! Automatic poweroff will be triggered in ${sshcs_opt_timeout_poweroff}s"
echo "To deactivate, please unlock devices" echo "To deactivate, please unlock devices"
echo ""
trap sshcs_trapped_timeout SIGALRM trap sshcs_trapped_timeout SIGALRM
( (
sleep ${sshcs_opt_timeout_poweroff} sleep ${sshcs_opt_timeout_poweroff}
@ -63,13 +98,25 @@ sshcs_trap_timeout() {
sshcs_untrap_timeout() { sshcs_untrap_timeout() {
[ -z "${pid_timeout}" ] && return 0 [ -z "${pid_timeout}" ] && return 0
kill ${pid_timeout} # Notes:
# If there was a running SSH shell, it may also try to kill it.
# This only kills the spawned subshell, leaving the 'sleep' command still
# running until done (which is not an issue).
proc_parse_stat ${pid_timeout} && kill ${pid_timeout}
pid_timeout=
trap - SIGALRM trap - SIGALRM
msg "Timeout cleared." msg "Timeout cleared."
} }
sshcs_dropbear_unlock() { sshcs_shell_run() {
local timeout_poweroff_min=120 sshcs_trap_timeout
# actual script (shared with SSH login) with which we can unlock devices
sshcs_unlocked_test=0
. "${sshcs_shell_script}"
}
sshcs_dropbear_run() {
local pid_timeout= local pid_timeout=
local dev_pts_mounted=0 local dev_pts_mounted=0
local listen= local listen=
@ -81,78 +128,43 @@ sshcs_dropbear_unlock() {
dev_pts_mounted=1 dev_pts_mounted=1
fi fi
# /etc/passwd file for the root user if [ ${sshcs_opt_use_shell} -eq 0 ]; then
echo "root:x:0:0:root:/root:${dropbear_login_shell}" > "/etc/passwd" sshcs_shell_script=${sshcs_cryptsetup_script}
echo "${dropbear_login_shell}" > "/etc/shells" else
cat <<EOF > "${sshcs_shell_script}"
# root login script
cat <<EOF > "${dropbear_login_shell}"
#!/usr/bin/ash #!/usr/bin/ash
. "/init_functions" . "/usr/local/bin/ssh-cryptsetup-tools"
if [ ! -f "${dropbear_cryptsetup_script}" ]; then
err "No cryptsetup script present! Please retry."
exit 0
fi
if [ -c "/dev/mapper/control" ]; then
CSQUIET=
. "${dropbear_cryptsetup_script}"
echo "" echo ""
echo "cryptsetup succeeded! Boot sequence should go on." echo "Call ${sshcs_cryptsetup_script} to try unlocking device(s)"
echo "Please wait and retry for standard SSH service."
else # Now give the user its shell
err "Device resources missing! Please retry." /usr/bin/ash
fi
echo "" # Check whether we are fully done
sshcs_check_done 1
EOF EOF
chmod a+x "${dropbear_login_shell}" chmod a+x "${sshcs_shell_script}"
fi
# /etc/passwd file for the root user
echo "root:x:0:0:root:/root:${sshcs_shell_script}" > "/etc/passwd"
echo "${sshcs_shell_script}" > "/etc/shells"
[ ! -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 -Esgjk -P "${path_dropbear_pid}" ${sshcs_opt_listen}
sshcs_trap_timeout # Actual unlocking shell
sshcs_shell_run
# 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
} }
sshcs_cryptpart_process() { sshcs_cryptpart_process() {
local cryptdev_orig cryptopt cryptargs
# ensure there is a device (handle 'UUID=' format) # ensure there is a device (handle 'UUID=' format)
[ -z "${cryptdev}" ] && return 0 [ -z "${cryptdev}" ] && return 0
[ "${cryptdev#UUID=}" != "${cryptdev}" ] && cryptdev="/dev/disk/by-uuid/${cryptdev#UUID=}" [ "${cryptdev#UUID=}" != "${cryptdev}" ] && cryptdev="/dev/disk/by-uuid/${cryptdev#UUID=}"
@ -161,7 +173,7 @@ sshcs_cryptpart_process() {
cryptargs= cryptargs=
for cryptopt in ${cryptoptions//,/ }; do for cryptopt in ${cryptoptions//,/ }; do
case ${cryptopt} in case ${cryptopt} in
allow-discards) discard)
cryptargs="${cryptargs} --allow-discards" cryptargs="${cryptargs} --allow-discards"
;; ;;
@ -178,26 +190,34 @@ sshcs_cryptpart_process() {
cryptdev_orig=${cryptdev} cryptdev_orig=${cryptdev}
if cryptdev=$(resolve_device "${cryptdev_orig}" ${rootdelay}); then if cryptdev=$(resolve_device "${cryptdev_orig}" ${rootdelay}); then
if cryptsetup isLuks "${cryptdev}" >/dev/null 2>&1; 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 # 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}"
#!/usr/bin/ash
. "/usr/local/bin/ssh-cryptsetup-tools"
cycle_or_retry() { 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 read -n 1 -s -t 5 -p "Within 5s press 'P' to poweroff, 'R' to reboot or any other key to retry. " res
echo "" echo ""
if [ "\${res}" = "P" ]; then [ "${res}" == "P" ] && poweroff -f
poweroff -f [ "${res}" == "R" ] && reboot -f
elif [ "\${res}" = "R" ]; then
reboot -f
fi
} }
try_unlock() {
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 [ \${sshcs_unlocked_test:-0} -eq 1 ]; then
sshcs_unlocked=0
return
fi
if cryptsetup open --type "${crypttype}" "${cryptdev}" "${cryptname}" ${cryptargs} "\${CSQUIET}"; then
if poll_device "/dev/mapper/${cryptname}" ${rootdelay}; then if poll_device "/dev/mapper/${cryptname}" ${rootdelay}; then
killall cryptsetup > /dev/null 2>&1 killall cryptsetup > /dev/null 2>&1
break break
@ -218,31 +238,8 @@ EOF
fi fi
} }
run_hook() { sshcs_cryptpart_setup() {
local etc_crypttab="/etc/crypttab" local cryptdev crypttype cryptname cryptpass cryptoptions
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
# sanity check: crypttab should be present
[ ! -e "${etc_crypttab}" ] && return 0
modprobe -a -q dm-crypt >/dev/null 2>&1
[ "${quiet}" = "y" ] && CSQUIET=">/dev/null"
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=
@ -256,15 +253,72 @@ run_hook() {
sshcs_cryptpart_process sshcs_cryptpart_process
done < "${etc_crypttab}" done < "${etc_crypttab}"
if [ ! -e "${dropbear_cryptsetup_script}" ]; then # Nothing else to do if there is no device we can unlock
[ -s "${sshcs_cryptsetup_script}" ] || return 0
cat <<'EOF' >> "${sshcs_cryptsetup_script}"
# No other device to unlock
}
if [ -c "/dev/mapper/control" ]; then
CSQUIET=
try_unlock
[ ${sshcs_unlocked_test:-0} -eq 1 ] && return
sshcs_check_done 0
else
if [ \${sshcs_unlocked_test:-0} -eq 1 ]; then
sshcs_unlocked=0
return
fi
echo ""
err "Device resources missing! Please retry."
fi
EOF
chmod a+x "${sshcs_cryptsetup_script}"
}
run_hook() {
local etc_crypttab="/etc/crypttab"
local path_dropbear_pid="/.dropbear.pid"
local sshcs_shell_script="/.sshcs_shell.sh"
local net_env="/.sshcs_net_env.sh"
local line net_device
local CSQUIET
# Note: options were loaded already
# sanity check: crypttab should be present
[ ! -e "${etc_crypttab}" ] && {
dbg "No crypttab configuration to process"
return 0
}
# Initialize random generator ASAP.
# May delay first SSH login by a few seconds otherwise.
(dd if=/dev/urandom of=/dev/null bs=4 count=1 status=none > /dev/null 2>&1) &
(dd if=/dev/random of=/dev/null bs=4 count=1 status=none > /dev/null 2>&1) &
modprobe -a -q dm-crypt >/dev/null 2>&1
[ "${quiet}" = "y" ] && CSQUIET=">/dev/null"
umask 0022
# Setup script used to unlock device either in console or SSH
sshcs_cryptpart_setup
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
sshcs_net_done 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_shell_run
return 0 return 0
fi fi
# time to unlock (through console or dropbear) # time to unlock (through console or dropbear)
sshcs_dropbear_unlock sshcs_dropbear_run
# stop the network before going on in boot sequence
sshcs_net_done
} }

View File

@ -0,0 +1,188 @@
#!/usr/bin/ash
. "/init_functions"
dbg () {
[ ${sshcs_opt_debug} != 0 ] && echo "$@"
}
sshcs_env_load() {
local sshcs_env="/etc/initcpio/sshcs_env"
local debug_default=0
local net_wol_default=g
local timeout_ipconfig_default=10
local timeout_poweroff_min=120
local use_shell_default=0
[ ${sshcs_env_loaded:-0} -eq 1 ] && return
[ -e "${sshcs_env}" ] && . "${sshcs_env}"
sshcs_env_loaded=1
[ -z "${sshcs_opt_debug}" ] && sshcs_opt_debug=${debug_default}
[ -z "${sshcs_opt_net_wol}" ] && sshcs_opt_net_wol=${net_wol_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_cryptsetup_script="/.sshcs_cryptsetup_script.sh"
}
proc_parse_stat() {
local unused
pid=$1
cmd=
ppid=
[ ! -e /proc/${pid}/stat ] && return 1
read unused cmd unused ppid unused < /proc/${pid}/stat
}
proc_find_parent_cmd() {
pid=$1
proc_parse_stat ${pid} || return 1
while [ ${ppid} -gt 1 ]
do
proc_parse_stat ${ppid} || return 1
if [ "${cmd}" == "($2)" ]; then
ppid=${pid}
pid=$1
return 0
fi
pid=${ppid}
done
return 1
}
proc_is_console() {
if [ -z "${is_console:-}" ]; then
# We are in console if we were not forked from dropbear.
is_console=1
proc_find_parent_cmd $$ "dropbear" && is_console=0
fi
[ "${is_console}" -eq 1 ]
}
sshcs_cleanup() {
local pgrep_output
# Reminders:
# We are called when devices have been unlocked.
#
# We are only called as part of the main shell (whether on console - the init
# script - or through SSH - as the user login shell), and once we return our
# parent shell will end.
#
# The unlocking script does 'killall cryptsetup' after each successful unlock,
# which is used to wakeup any other running unlocking script.
# Thus as long as all devices have been unlocked, we don't expect any script
# to be stuck on 'cryptsetup' calls.
if proc_is_console; then
# We are in the console.
# It is time to properly end the processes we started and files we created.
# When using a shell - instead of directly calling the unlocking script -
# we also need to signal any SSH shell so that it is properly cleaned too.
# cleanup dropbear
if [ -f "${path_dropbear_pid}" ]; then
msg "Stopping dropbear ..."
kill $(cat "${path_dropbear_pid}")
rm -f "${path_dropbear_pid}"
fi
if [ ${sshcs_opt_use_shell} -eq 1 ]; then
# Find and kill all shells spawned by SSH.
# This is necessary to properly terminate both these shells and the spawned
# SSH processes.
# Reminder: "... | ..." does fork a subshell
dbg "Searching SSH shells ..."
pgrep_output=$(pgrep /usr/bin/ash)
pgrep_output=$(echo "${pgrep_output}" | grep -E -v "^(|1|$$)$")
echo "${pgrep_output}" | while read pid; do
proc_parse_stat ${pid} || continue
proc_find_parent_cmd ${pid} "dropbear" || continue
dbg "Killing SSH shell pid=${pid}"
kill -SIGHUP ${pid}
done
fi
# cleanup /dev/pts if necessary
if [ ${dev_pts_mounted} -ne 0 ]; then
umount "/dev/pts"
rm -R "/dev/pts"
fi
# stop the network before going on in boot sequence
sshcs_net_done
rm -f "${sshcs_cryptsetup_script}" "${sshcs_shell_script}" "/etc/passwd" "/etc/shells" "/var/log/lastlog"
elif [ ${sshcs_opt_use_shell} -eq 1 ]; then
# We are in a SSH shell session.
# Find and kill console shell.
# This is necessary so that our script launched from the init process can
# finally check that devices have been properly unlocked, properly end and
# let the init process end booting.
# Note: as a side effect, this will also kill the shell that was forked to
# trigger a timeout, which is fine (we want to kill it, either from here or
# from the init shell).
dbg "Searching console shells ..."
pgrep_output=$(pgrep /usr/bin/ash)
pgrep_output=$(echo "${pgrep_output}" | grep -E -v "^(|1|$$)$")
echo "${pgrep_output}" | while read pid; do
proc_find_parent_cmd ${pid} "dropbear" && continue
dbg "Killing console shell pid=${pid}"
kill -SIGHUP ${pid}
done
fi
# else: when in SSH shell script, we have nothing else to do other than exit.
}
sshcs_check_done() {
# Whether we are called from the main script: that is whether the shell will
# end when we return.
local finalize=$1
# This is always the main script when not using shell
[ ${sshcs_opt_use_shell} -eq 0 ] && finalize=1
# Reset timeout when applicable: only possible from init script.
proc_is_console && type sshcs_untrap_timeout > /dev/null 2>&1 && sshcs_untrap_timeout
# Check devices are unlocked.
sshcs_unlocked_test=1
sshcs_unlocked=1
. "${sshcs_cryptsetup_script}"
if [ ${sshcs_unlocked} -ne 1 ]; then
echo ""
# When finalizing in console, power off
if [ ${finalize} -eq 1 ] && proc_is_console; then
err "Devices are still locked! Powering off."
poweroff -f
fi
# When in shell or SSH, let user try again
err "Devices are still locked! Please retry."
return
fi
if [ ${finalize} -eq 0 ]; then
# Kill our parent (the interactive shell); the script that launched it will
# do finalization.
proc_parse_stat $$
kill -SIGHUP ${ppid}
exit 0
fi
echo ""
echo "cryptsetup succeeded! Boot sequence should go on."
proc_is_console || echo "Please wait and reconnect to nominal SSH service."
sshcs_cleanup
}
sshcs_env_load

View File

@ -31,8 +31,8 @@ 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=( "rsa" "ecdsa" "ed25519" )
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"
local openssh_keyfile_prefix="/etc/ssh/ssh_host_" local openssh_keyfile_prefix="/etc/ssh/ssh_host_"
@ -52,42 +52,71 @@ build() {
sshcs_check_keys sshcs_check_keys
add_checked_modules "/drivers/net/" # Note: parts of this script (modules/binaries/files added) are the same than
add_module dm-crypt # other install scripts (/usr/lib/initcpio/install/):
# Note: crypto modules are necessary # - 'encryp': nominal support of encrypted volumes at boot time
if [ -n "${CRYPTO_MODULES}" ]; then # - 'net': network tools
## Modules
# (from 'encrypt')
add_module 'dm-crypt'
add_module 'dm-integrity'
if [[ $CRYPTO_MODULES ]]; then
local mod local mod
for mod in ${CRYPTO_MODULES}; do for mod in $CRYPTO_MODULES; do
add_module "${mod}" add_module "$mod"
done done
else else
add_all_modules "/crypto/" add_all_modules '/crypto/'
fi fi
# Note: dmsetup is necessary for device mapper features # (from 'net')
add_binary "cryptsetup" add_checked_modules '/drivers/net/'
add_binary "dmsetup"
add_binary "dropbear"
add_binary "ip"
add_binary "/usr/lib/initcpio/ipconfig" "/sbin/ipconfig"
# auth-related files
add_file "/lib/libnss_files.so" ## Binaries
# (from 'encrypt')
add_binary 'cryptsetup'
# cryptsetup calls pthread_create(), which dlopen()s libgcc_s.so.1
# Note: at least necessary for LUKS v2 volumes.
# Also see similar/related bug reports (e.g. https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=950254).
add_binary '/usr/lib/libgcc_s.so.1'
# (from 'net')
add_binary '/usr/lib/initcpio/ipconfig' '/bin/ipconfig'
# (ours)
# Note: dmsetup is necessary for device mapper features
add_binary 'dmsetup'
add_binary 'dropbear'
add_binary 'ip'
add_binary 'ethtool'
## Other files
# (from 'encrypt')
# cryptsetup-related files
map add_udev_rule \
'10-dm.rules' \
'13-dm-disk.rules' \
'95-dm-notify.rules' \
'/usr/lib/initcpio/udev/11-dm-initramfs.rules'
# (ours)
# Our script and options
[ -e "${sshcs_env}" ] && add_file "${sshcs_env}"
# Note: use /usr/local/bin, even though everything actually points to /usr/bin
# in initramfs.
add_file '/usr/lib/initcpio/hooks/ssh-cryptsetup-tools' '/usr/local/bin/ssh-cryptsetup-tools'
# 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}" for keytype in "${dropbear_key_types[@]}"; do
add_file "/etc/dropbear/dropbear_rsa_host_key" add_file "${dropbear_keyfile_prefix}${keytype}${dropbear_keyfile_suffix}"
add_file "/etc/dropbear/dropbear_dss_host_key" done
add_file "/etc/dropbear/dropbear_ecdsa_host_key"
# cryptsetup-related files # crypt partitions
add_file "${etc_crypttab}" 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 add_runscript
} }
@ -101,16 +130,30 @@ 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_listen': listening port (22 by default) * 'sshcs_opt_debug': whether to be more verbose about ongoing actions
* 'sshcs_opt_timeout_poweroff': time (s) to unlock devices before automatic - default: '0'
powering off - any non-zero value to enable
- default (and minimum value): 2 minutes * 'sshcs_opt_net_wol': Wake-on-LAN option to set on network device
- default: 'g' (MagicPacket™)
- usually WOL is disabled once in initramfs shell
- set empty to not change network device WOL setting
* 'sshcs_opt_timeout_ipconfig': time (in seconds) to configure IP
- default: '10'
* '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): '120' (2 minutes)
- negative value to deactivate - negative value to deactivate
* 'sshcs_opt_use_shell': whether to start a full 'ash' shell
- default: '0'
- '1' to enable
- when disabled (the default), a script to unlock devices is executed instead
Each SSH server key ('dropbear_rsa_host_key', 'dropbear_dss_host_key' and Each SSH server key ('dropbear_rsa_host_key', 'dropbear_ecdsa_host_key' and
'dropbear_ecdsa_host_key' in '/etc/dropbear' folder) is imported from OpenSSH 'dropbear_ed25519_host_key' in '/etc/dropbear' folder) is imported from OpenSSH
if present or generated if missing. Fingerprints are displayed upon building if present or generated if missing. Fingerprints are displayed upon building
the initramfs image. the initramfs image.
EOF EOF