16 Commits
0.9-2 ... 1.2-1

Author SHA1 Message Date
Julien Coloos
00e8c1f97c v1.2-1 2026-07-12 20:26:55 +02:00
Julien Coloos
d69f71b561 Reduce network device speed to 10M for WoL
In previous Arch/kernel versions, the network device speed was
automatically set to the lowest possible upon poweroff when WoL was
enabled.

Latest versions do keep the network device to its standard speed (1000M
for example), which consumes some useless power when computer is powered
off and WoL enabled.

Force speed lowering for WoL.
But restore it before continuing boot, when devices are unlocked,
otherwise it remains as-is.

Make it an option, to select the wanted speed, or leave it as-is.
2026-07-12 20:20:32 +02:00
Julien Coloos
cdc0b4c427 Fixed and added some comments 2026-07-12 20:20:21 +02:00
Julien Coloos
d5f066f066 Fix kernel panic when network setup fails
If there is no network, we skip the dropbear (SSH) part and only want to
allow unlocking on console.
However, with previous changes/refactoring, in this case the script to
run was not properly set up as expected.

Moved the concerned code so that script setup is performed in all cases.

Also do a last check to warn and skip in case of missing script, which
is preferable to a kernel panic.
2026-07-12 20:17:11 +02:00
Julien Coloos
14a74a0385 Fixed a few variables declaration/reading
Depending on configuration and what happens, some variable may not be
initialized.
2026-07-12 20:15:29 +02:00
Julien Coloos
6c1945a787 Wait 2s before powering off.
So that message is visible if user is on console.
2026-07-12 20:14:00 +02:00
Julien Coloos
3763703471 Refactor README
Add new option, and have install script mention README for details.
2026-07-12 20:12:58 +02:00
Julien Coloos
2335b859fa Refactor messages printing/logging
Add option to also log to ksmg.
2026-07-12 20:08:40 +02:00
Julien Coloos
32f45a9121 v1.1-2 2025-11-15 15:20:36 +01:00
Julien Coloos
7d866bdfca Use full version (pkgver and pkgrel) for source archive name
Sometimes we need to change the sources, but only for minor external
dependencies diff (e.g. adding/removing upstream source), in which
case we wish to only bump pkgrel.
2025-11-15 15:14:07 +01:00
Julien Coloos
8e5153d002 Removed 11-dm-initramfs.rules, which was added to 10-dm.rules
See: 589e0397ea
2025-11-15 15:12:46 +01:00
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
6 changed files with 733 additions and 382 deletions

View File

@@ -1,62 +1,115 @@
2026-07-12 Julien Coloos <julien.coloos [at] gmail [dot] com>
* v1.2-1
New option to log some messages to kmsg too.
Change network speed to 10M during boot, to reduce consumption upon WoL.
2025-11-15 Julien Coloos <julien.coloos [at] gmail [dot] com>
* v1.1-2
Removed 11-dm-initramfs.rules, which was added to 10-dm.rules.
See: https://gitlab.archlinux.org/archlinux/mkinitcpio/mkinitcpio/-/commit/589e0397ea55e61a08fdbcab52ad4639d382f08e
Use full version (pkgver and pkgrel) for source archive name.
Sometimes we need to change the sources, but only for minor external
dependencies diff (e.g. adding/removing upstream source), in which
case we wish to only bump pkgrel.
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> 2021-10-24 Julien Coloos <julien.coloos [at] gmail [dot] com>
* v0.9-1 * v0.9-1
Try to print network devices information when interface setup fails Try to print network devices information when interface setup fails.
2021-08-15 Julien Coloos <julien.coloos [at] gmail [dot] com> 2021-08-15 Julien Coloos <julien.coloos [at] gmail [dot] com>
* v0.8-1 * v0.8-1
Include 'libgcc_s.so.1' which is necessary for (at least) proper LUKS v2 handling 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> 2020-07-14 Julien Coloos <julien.coloos [at] gmail [dot] com>
* v0.7-1 * v0.7-1
Dropped 'dsa' private key support; added 'ed25519' private key support Dropped 'dsa' private key support; added 'ed25519' private key support.
2018-03-13 Julien Coloos <julien.coloos [at] gmail [dot] com> 2018-03-13 Julien Coloos <julien.coloos [at] gmail [dot] com>
* v0.6-1 * v0.6-1
Dropped '-m' option when calling dropbear (latest ArchLinux version does not handle it) Dropped '-m' option when calling dropbear (latest ArchLinux version
does not handle it).
2017-06-25 Julien Coloos <julien.coloos [at] gmail [dot] com> 2017-06-25 Julien Coloos <julien.coloos [at] gmail [dot] com>
* v0.5-1 * v0.5-1
Fixed cryptsetup additional arguments handling: were not properly passed Fixed cryptsetup additional arguments handling: were not properly
passed.
2017-06-25 Julien Coloos <julien.coloos [at] gmail [dot] com> 2017-06-25 Julien Coloos <julien.coloos [at] gmail [dot] com>
* v0.4-1 * v0.4-1
Fixed TRIM option handling in /etc/crypttab: 'discard' ('allow-discards' being the switch name to use in cryptsetup) 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> 2015-11-22 Julien Coloos <julien.coloos [at] gmail [dot] com>
* v0.3-1 * v0.3-1
Added configurable timeout for ipconfig Added configurable timeout for ipconfig.
Moved configuration file from /etc/dropbear/initrd.env to /etc/initcpio/sshcs_env 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.9 pkgver=1.2
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-$pkgrel.tar.xz" "$pkgname.install")
md5sums=('c94a905ca91f7afe2c0f771bd5182cb2' sha256sums=('94156250bfc04490801d8575192a787363cf4637ade2473147d3f63924c5f814'
'ac60109d80e7bb2af0d66e69aaf178a6') '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,31 @@
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 legacy dropbear_initrd_encrypt AUR package. 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, e.g.: After cloning the repo, installation is done as for an AUR package, e.g.:
```bash
makepkg -sri makepkg -sri
```
## Dropbear ## Dropbear
SSH server key need to be generated for `dropbear`. SSH server key need to be generated for `dropbear`.
Either a new key can be generated with `dropbearkey`, e.g.: Either a new key can be generated with `dropbearkey`, e.g.:
```bash
dropbearkey -t ecdsa -f /etc/dropbear/dropbear_ecdsa_host_key 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.: Or an existing OpenSSH key can be converted with `dropbearconvert` (useful so that the server fingerprint is the same with both), e.g.:
```bash
dropbearconvert openssh dropbear /etc/ssh/ssh_host_ecdsa_key /etc/dropbear/dropbear_ecdsa_host_key dropbearconvert openssh dropbear /etc/ssh/ssh_host_ecdsa_key /etc/dropbear/dropbear_ecdsa_host_key
```
Notes: Notes:
* `rsa` and `ed25519` types are also handled * `rsa` and `ed25519` types are also handled
* OpenSSH keys must be in `PEM` format for `dropbearconvert` to properly work * 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`: If necessary an existing key file can be converted to `PEM` format using `ssh-keygen`:
```bash
ssh-keygen -A -p -m PEM -f /etc/ssh/ssh_host_ecdsa_key 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:
@@ -37,32 +39,54 @@ 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/initcpio/sshcs_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_log_kmsg`: whether to log (debug, info, error) messages to kmsg too
- default: `1`
- many messages are only printed on console and are not concerned
- by default (debug disabled), only useful messages are concerned
- set `0` to disable
* `sshcs_opt_debug`: whether to be more verbose about ongoing actions * `sshcs_opt_debug`: whether to be more verbose about ongoing actions
- default: 0 - default: `0`
- any non-zero value to enable - 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_net_speed`: speed to set on network device
- default: `10`
- full duplex is enabled, and auto-negociation disabled
- latest Arch/kernel tend to keep the speed at 1000M even during WoL
- this only applies to boot phase and persists for WoL: when unlocking devices, the network is reconfigured before the OS is fully ready
- set `0` to not change network device speed
* `sshcs_opt_timeout_ipconfig`: time (in seconds) to configure IP * `sshcs_opt_timeout_ipconfig`: time (in seconds) to configure IP
- default: 10 seconds - 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:
```bash
sshcs_opt_timeout_ipconfig=30 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 ## Building notes
1. Modify the sources (features in `src`, and/or package building files) 1. Modify the sources (features in `src`, and/or package building files)
2. If `src` was modified 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` * bump `pkgver`, or `pkgrel`, in `PKGBUILD`
* archive the `src` folder in `$pkgname-$pkgver-$pkgrel.tar.xz` file; e.g.: `tar -cJf initrd-ssh-cryptsetup-$(grep "^pkgver=" PKGBUILD | cut -d'=' -f2)-$(grep "^pkgrel=" PKGBUILD | cut -d'=' -f2).tar.xz src`
* upload the archive on the online repository (pointed by `PKGBUILD`) * upload the archive on the online repository (pointed by `PKGBUILD`)
3. Update ChangeLog 3. Update ChangeLog
4. Update `PKGBUILD` 4. Update `PKGBUILD`
* bump `pkgver` if `src` was modified, or `pkgrel` if building files were modified * bump `pkgrel` if only building files were modified
* refresh `md5sums` if necessary (based on `md5sum initrd-ssh-cryptsetup-*.tar.xz initrd-ssh-cryptsetup.install` output) * 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 5. Delete generated archive file if any

View File

@@ -1,311 +1,352 @@
#!/usr/bin/ash #!/usr/bin/ash
dbg () { . "/usr/local/bin/ssh-cryptsetup-tools"
[ ${sshcs_opt_debug} != 0 ] && echo "$@"
}
sshcs_env_load() {
local debug_default=0
local timeout_ipconfig_default=10
local timeout_poweroff_min=120
[ -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}
[ ${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 local iparg net_address ipconfig_out net_netmask net_gateway net_dns0 net_dns1
[ -z "${ip}" ] && [ -n "${nfsaddrs}" ] && ip="${nfsaddrs}"
[ -z "${ip}" ] && {
dbg "No ip setting to setup network"
return 1
}
net_device=$(echo ${ip} | cut -d: -f6) # we must have an 'ip' setting, and a device in it
[ -z "${net_device}" ] && { [ -z "${ip}" ] && [ -n "${nfsaddrs}" ] && ip="${nfsaddrs}"
dbg "No network device to setup" [ -z "${ip}" ] && {
return 1 log_dbg "No ip setting to setup network"
} return 1
}
# Setup network and save some values net_device=$(echo ${ip} | cut -d: -f6)
# Note: some useful redirection means ('< <(...)' and '<<< "$(...)"') are [ -z "${net_device}" ] && {
# not supported in the available shell. So we have to write code in a log_dbg "No network device to setup"
# temporary file and 'source' it since '... | while read ...' spawns a return 1
# subshell from which outer variables cannot be altered. }
: > "${net_env}"
echo "" # Note: ethtool can access WoL settings right now, but not other settings
echo "Configuring IP (timeout = ${sshcs_opt_timeout_ipconfig}s) ..." # until the network is setup.
# ipconfig manual: https://git.kernel.org/pub/scm/libs/klibc/klibc.git/tree/usr/kinit/ipconfig/README.ipconfig if [ "${sshcs_opt_net_wol:-d}" != "d" ]; then
ipconfig_out=$(ipconfig -t "${sshcs_opt_timeout_ipconfig}" "ip=${ip}") log_dbg "Setting network device=${net_device} wol=${sshcs_opt_net_wol}"
if [ $? -ne 0 ]; then ethtool -s "${net_device}" wol "${sshcs_opt_net_wol}"
err "IP configuration timeout!" fi
echo "Devices probing:"
ipconfig -n -t 5 -c none all
return 1
fi
echo -n "${ipconfig_out}" | while read line; do # Setup network and save some values
[ "${line#"IP-Config:"}" != "${line}" ] && continue # 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
log_err "IP configuration timeout!"
echo "Devices probing:"
ipconfig -n -t 5 -c none all
return 1
fi
for iparg in ${line}; do echo -n "${ipconfig_out}" | while read line; do
case "${iparg}" in [ "${line#"IP-Config:"}" != "${line}" ] && continue
address=*|netmask=*|gateway=*|dns0=*|dns1=*)
echo "net_${iparg}" >> "${net_env}" line="$(echo "${line}" | sed -e 's/ :/:/g;s/: /=/g')"
;;
esac for iparg in ${line}; do
done case "${iparg}" in
address=*|netmask=*|gateway=*|dns0=*|dns1=*)
echo "net_${iparg}" >> "${net_env}"
;;
esac
done done
done
. "${net_env}" . "${net_env}"
rm -f "${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}" log_msg "IP-Config: device=${net_device} ip=${net_address}/${net_netmask} gw=${net_gateway} dns0=${net_dns0} dns1=${net_dns1}"
[ -n "${net_address}" ] # Ensure we have an address
[ -n "${net_address}" ] || return 1
# Note: We cannot change the device settings, other than WoL, before the
# network is setup.
if [ ${sshcs_opt_net_speed} != 0 ]; then
log_dbg "Setting network device=${net_device} speed=${sshcs_opt_net_speed}"
ethtool -s "${net_device}" speed "${sshcs_opt_net_speed}" duplex full autoneg off
fi
} }
sshcs_net_done() { sshcs_net_done() {
# we are done with the network # we are done with the network
if [ -n "${net_device}" ]; then if [ -n "${net_device}" ]; then
dbg "Setting network device=${net_device} down" log_dbg "Setting network device=${net_device} down"
ip addr flush dev "${net_device}" ip addr flush dev "${net_device}"
ip link set dev "${net_device}" down ip link set dev "${net_device}" down
fi fi
} }
sshcs_trapped_timeout() { sshcs_trapped_timeout() {
err "Timeout reached! Powering off." log_err "Timeout reached! Powering off."
poweroff -f sleep 2
exit poweroff -f
exit
} }
sshcs_trap_timeout() { sshcs_trap_timeout() {
local pid_init=$$ local pid_init=$$
if [ ${sshcs_opt_timeout_poweroff} -gt 0 ]; then if [ ${sshcs_opt_timeout_poweroff} -gt 0 ]; then
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 (
( # Wait for timeout
sleep ${sshcs_opt_timeout_poweroff} sleep ${sshcs_opt_timeout_poweroff}
kill -SIGALRM ${pid_init} # Signal process (triggers poweroff)
# Signal is not processed if cryptsetup is waiting for the password kill -SIGALRM ${pid_init}
killall cryptsetup > /dev/null 2>&1 # Note: signal is not processed if cryptsetup is waiting for the password
) & killall cryptsetup > /dev/null 2>&1
pid_timeout=$! ) &
fi pid_timeout=$!
fi
} }
sshcs_untrap_timeout() { sshcs_untrap_timeout() {
[ -z "${pid_timeout}" ] && return 0 [ -z "${pid_timeout:-}" ] && return 0
kill ${pid_timeout} # Notes:
trap - SIGALRM # If there was a running SSH shell, it may also try to kill it.
msg "Timeout cleared." # 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
log_dbg "Timeout cleared."
} }
sshcs_unlock() { sshcs_shell_run() {
sshcs_trap_timeout sshcs_trap_timeout
# actual script (shared with SSH login) unlocking encrypted devices # actual script (shared with SSH login) with which we can unlock devices
. "${sshcs_cryptsetup_script}" sshcs_unlocked_test=0
log_dbg "Running ${sshcs_shell_script}"
sshcs_untrap_timeout # Belt and suspenders: if the script does not exist, trying to source it
# actually triggers a kernel panic.
if [ ! -e "${sshcs_shell_script}" ]; then
log_err "No script to run! ${sshcs_shell_script} does not exist!"
return
fi
. "${sshcs_shell_script}"
} }
sshcs_dropbear_unlock() { sshcs_dropbear_run() {
local pid_timeout= local dev_pts_mounted=0
local dev_pts_mounted=0 local listen=
local listen=
# ensure /dev/pts is present # ensure /dev/pts is present
if [ ! -d "/dev/pts" ]; then if [ ! -d "/dev/pts" ]; then
mkdir -p "/dev/pts" mkdir -p "/dev/pts"
mount -t devpts devpts "/dev/pts" mount -t devpts devpts "/dev/pts"
dev_pts_mounted=1 dev_pts_mounted=1
fi fi
# /etc/passwd file for the root user # /etc/passwd file for the root user
echo "root:x:0:0:root:/root:${dropbear_login_shell}" > "/etc/passwd" echo "root:x:0:0:root:/root:${sshcs_shell_script}" > "/etc/passwd"
echo "${dropbear_login_shell}" > "/etc/shells" echo "${sshcs_shell_script}" > "/etc/shells"
# root login script [ ! -d "/var/log" ] && mkdir -p "/var/log"
cat <<EOF > "${dropbear_login_shell}" touch "/var/log/lastlog"
#!/usr/bin/ash
. "/init_functions" log_dbg "Starting dropbear ..."
dropbear -Esgjk -P "${path_dropbear_pid}" ${sshcs_opt_listen}
if [ ! -f "${sshcs_cryptsetup_script}" ]; then # Actual unlocking shell
err "No cryptsetup script present! Please retry." sshcs_shell_run
exit 0
fi
if [ -c "/dev/mapper/control" ]; then
CSQUIET=
. "${sshcs_cryptsetup_script}"
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."
fi
echo ""
EOF
chmod a+x "${dropbear_login_shell}"
[ ! -d "/var/log" ] && mkdir -p "/var/log"
touch "/var/log/lastlog"
msg "Starting dropbear ..."
dropbear -Esgjk -P "${path_dropbear_pid}" ${sshcs_opt_listen}
# Actual unlocking
sshcs_unlock
# 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_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_cryptpart_process() { sshcs_cryptpart_process() {
# ensure there is a device (handle 'UUID=' format) local cryptdev_orig cryptopt cryptargs
[ -z "${cryptdev}" ] && return 0
[ "${cryptdev#UUID=}" != "${cryptdev}" ] && cryptdev="/dev/disk/by-uuid/${cryptdev#UUID=}"
# get crypt options # ensure there is a device (handle 'UUID=' format)
cryptargs= [ -z "${cryptdev}" ] && return 0
for cryptopt in ${cryptoptions//,/ }; do [ "${cryptdev#UUID=}" != "${cryptdev}" ] && cryptdev="/dev/disk/by-uuid/${cryptdev#UUID=}"
case ${cryptopt} in
discard)
cryptargs="${cryptargs} --allow-discards"
;;
luks) # get crypt options
;; cryptargs=
for cryptopt in ${cryptoptions//,/ }; do
case ${cryptopt} in
discard)
cryptargs="${cryptargs} --allow-discards"
;;
*) luks)
echo "Device ${cryptdev} encryption option '${cryptopt}' not known, ignoring." ;;
;;
esac
done
# ensure device is encrypted and handled *)
cryptdev_orig=${cryptdev} echo "Device ${cryptdev} encryption option '${cryptopt}' not known, ignoring."
if cryptdev=$(resolve_device "${cryptdev_orig}" ${rootdelay}); then ;;
if cryptsetup isLuks "${cryptdev}" >/dev/null 2>&1; then esac
dbg "Adding crypt device=${cryptdev} type=${crypttype} name=${cryptname} args=<${cryptargs}> in setup script" 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
log_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 "${sshcs_cryptsetup_script}" ] || cat <<'EOF' > "${sshcs_cryptsetup_script}"
#!/usr/bin/ash
. "/usr/local/bin/ssh-cryptsetup-tools"
# update script used to unlock device either in console or SSH
[ -s "${sshcs_cryptsetup_script}" ] || cat <<EOF > "${sshcs_cryptsetup_script}"
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 >> "${sshcs_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 [ \${sshcs_unlocked_test:-0} -eq 1 ]; then
sshcs_unlocked=0
return
fi
if cryptsetup open --type "${crypttype}" "${cryptdev}" "${cryptname}" ${cryptargs} "\${CSQUIET}"; then 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
fi
err "Device still not mapped! Please wait or retry."
elif [ ! -e "/dev/mapper/${cryptname}" ]; then
err "cryptsetup failed! Please retry."
else
break break
fi
log_err "Device still not mapped! Please wait or retry."
elif [ ! -e "/dev/mapper/${cryptname}" ]; then
log_err "cryptsetup failed! Please retry."
else
break
fi fi
cycle_or_retry cycle_or_retry
done done
EOF EOF
else else
err "Failed to manage encrypted device ${cryptdev_orig}: not a LUKS volume." log_err "Failed to manage encrypted device ${cryptdev_orig}: not a LUKS volume."
fi
fi fi
fi
}
sshcs_cryptpart_setup() {
local cryptdev crypttype cryptname cryptpass cryptoptions
# Notes:
# The script is built piece by piece to unlock each target device.
# If there is no device to unlock, there is no script, and boot should simply
# go on as usual.
# 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}"
# Nothing else to do if there is no device we can unlock
[ -s "${sshcs_cryptsetup_script}" ] || return 0
# There were deviced to unlock.
# We can now finish the script.
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 ""
log_err "Device resources missing! Please retry."
fi
EOF
chmod a+x "${sshcs_cryptsetup_script}"
if [ ${sshcs_opt_use_shell} -eq 0 ]; then
# The script we built *is* the shell to run.
sshcs_shell_script=${sshcs_cryptsetup_script}
else
# User will have a full shell, and can call the script if needed.
cat <<EOF > "${sshcs_shell_script}"
#!/usr/bin/ash
. "/usr/local/bin/ssh-cryptsetup-tools"
echo ""
echo "Call ${sshcs_cryptsetup_script} to try unlocking device(s)"
# Now give the user its shell
/usr/bin/ash
# Check whether we are fully done
sshcs_check_done 1
EOF
chmod a+x "${sshcs_shell_script}"
fi
} }
run_hook() { run_hook() {
local etc_crypttab="/etc/crypttab" local etc_crypttab="/etc/crypttab"
local sshcs_env="/etc/initcpio/sshcs_env" local path_dropbear_pid="/.dropbear.pid"
local path_dropbear_pid="/.dropbear.pid" local sshcs_shell_script="/.sshcs_shell.sh"
local dropbear_login_shell="/.cryptsetup_shell.sh" local net_env="/.sshcs_net_env.sh"
local sshcs_cryptsetup_script="/.cryptsetup_script.sh" local line net_device
local net_env="/.net_env.sh" local CSQUIET
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 # Note: options were loaded already
sshcs_env_load
# sanity check: crypttab should be present # sanity check: crypttab should be present
[ ! -e "${etc_crypttab}" ] && { [ ! -e "${etc_crypttab}" ] && {
dbg "No crypttab configuration to process" log_dbg "No crypttab configuration to process"
return 0 return 0
} }
modprobe -a -q dm-crypt >/dev/null 2>&1 # Initialize random generator ASAP.
[ "${quiet}" = "y" ] && CSQUIET=">/dev/null" # 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) &
umask 0022 modprobe -a -q dm-crypt >/dev/null 2>&1
[ "${quiet}" = "y" ] && CSQUIET=">/dev/null"
# check encrypted devices to handle umask 0022
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 # Setup script used to unlock device either in console or SSH
done < "${etc_crypttab}" sshcs_cryptpart_setup
if [ ! -e "${sshcs_cryptsetup_script}" ]; then
log_err "No encrypted device found! Skipping crypt remote unlocking."
return 0
fi
if [ ! -e "${sshcs_cryptsetup_script}" ]; then # start and check network
err "No encrypted device found! Skipping crypt remote unlocking." if ! sshcs_net_start; then
return 0 log_err "Net interface not available! Skipping crypt remote unlocking."
fi # We still allow to unlock locally with timeout
sshcs_shell_run
return 0
fi
# start and check network # time to unlock (through console or dropbear)
if ! sshcs_net_start; then sshcs_dropbear_run
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

@@ -0,0 +1,221 @@
#!/usr/bin/ash
. "/init_functions"
# Log debug message, if debug enabled.
# Also log as kmsg if enabled.
log_dbg() {
[ ${sshcs_opt_debug} -eq 0 ] && return 0
echo "$@"
[ ${sshcs_opt_log_kmsg} -eq 0 ] && return 0
echo "<31>sshcs: $@" > /dev/kmsg
}
# Log information message, even if quiet.
# Also log as kmsg if enabled.
log_msg() {
echo "$@"
[ ${sshcs_opt_log_kmsg} -eq 0 ] && return 0
echo "<30>sshcs: $@" > /dev/kmsg
}
# Log error message (prefixed with "ERROR: " in console).
# Also log as kmsg if enabled.
log_err() {
err "$@"
[ ${sshcs_opt_log_kmsg} -eq 0 ] && return 0
echo "<27>sshcs: $@" > /dev/kmsg
}
sshcs_env_load() {
local sshcs_env="/etc/initcpio/sshcs_env"
local log_kmsg_default=1
local debug_default=0
local net_wol_default=g
local net_speed_default=10
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_log_kmsg}" ] && sshcs_opt_log_kmsg=${log_kmsg_default}
[ -z "${sshcs_opt_debug}" ] && sshcs_opt_debug=${debug_default}
[ -z "${sshcs_opt_net_wol}" ] && sshcs_opt_net_wol=${net_wol_default}
[ -z "${sshcs_opt_net_speed}" ] && sshcs_opt_net_speed=${net_speed_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 we did change the network speed, time to reset it.
if [ -n "${net_device}" ] && [ ${sshcs_opt_net_speed} != 0 ]; then
log_dbg "Restoring network device=${net_device} speed"
ethtool -s "${net_device}" autoneg on
fi
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
log_dbg "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
log_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
log_dbg "Killing SSH shell pid=${pid}"
kill -SIGHUP ${pid}
done
fi
# cleanup /dev/pts if necessary
if [ ${dev_pts_mounted:-0} -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).
log_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
log_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.
log_dbg "All done"
}
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
log_err "Devices are still locked! Powering off."
poweroff -f
fi
# When in shell or SSH, let user try again
log_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 ""
log_msg "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

@@ -1,109 +1,127 @@
#!/bin/bash #!/bin/bash
sshcs_check_nonempty() { 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() { sshcs_check_keys() {
local dropbear_keyfile local dropbear_keyfile
local openssh_keyfile local openssh_keyfile
local fingerprint local fingerprint
for keytype in "${dropbear_key_types[@]}"; do for keytype in "${dropbear_key_types[@]}"; do
dropbear_keyfile=${dropbear_keyfile_prefix}${keytype}${dropbear_keyfile_suffix} dropbear_keyfile=${dropbear_keyfile_prefix}${keytype}${dropbear_keyfile_suffix}
openssh_keyfile=${openssh_keyfile_prefix}${keytype}${openssh_keyfile_suffix} openssh_keyfile=${openssh_keyfile_prefix}${keytype}${openssh_keyfile_suffix}
# Prefer OpenSSH keys, or generate missing ones # Prefer OpenSSH keys, or generate missing ones
if [ -e "${openssh_keyfile}" ]; then if [ -e "${openssh_keyfile}" ]; then
#echo "Copying OpenSSH ${keytype} host key for dropbear ..." #echo "Copying OpenSSH ${keytype} host key for dropbear ..."
dropbearconvert openssh dropbear "${openssh_keyfile}" "${dropbear_keyfile}" > /dev/null 2>&1 dropbearconvert openssh dropbear "${openssh_keyfile}" "${dropbear_keyfile}" > /dev/null 2>&1
elif [ ! -e "${dropbear_keyfile}" ]; then elif [ ! -e "${dropbear_keyfile}" ]; then
#echo "Generating ${keytype} host key for dropbear ..." #echo "Generating ${keytype} host key for dropbear ..."
dropbearkey -t "${keytype}" -f "${dropbear_keyfile}" > /dev/null 2>&1 dropbearkey -t "${keytype}" -f "${dropbear_keyfile}" > /dev/null 2>&1
fi fi
fingerprint=$(dropbearkey -y -f "${dropbear_keyfile}" | sed -n '/^Fingerprint:/ {s/Fingerprint: *//; p}') fingerprint=$(dropbearkey -y -f "${dropbear_keyfile}" | sed -n '/^Fingerprint:/ {s/Fingerprint: *//; p}')
echo "$(basename "${dropbear_keyfile}") : ${fingerprint}" echo "$(basename "${dropbear_keyfile}") : ${fingerprint}"
done done
} }
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 sshcs_env="/etc/initcpio/sshcs_env" local sshcs_env="/etc/initcpio/sshcs_env"
local dropbear_key_types=( "rsa" "ecdsa" "ed25519" ) 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_"
local openssh_keyfile_suffix="_key" local openssh_keyfile_suffix="_key"
# Check we are needed # Check we are needed
if ! sshcs_check_nonempty "${dropbear_authorized_keys}"; then if ! sshcs_check_nonempty "${dropbear_authorized_keys}"; then
echo "There is no root key(s) in ${dropbear_authorized_keys}. Skipping." echo "There is no root key(s) in ${dropbear_authorized_keys}. Skipping."
return 0 return 0
fi fi
if ! sshcs_check_nonempty "${etc_crypttab}"; then if ! sshcs_check_nonempty "${etc_crypttab}"; then
echo "There is no device in ${etc_crypttab}. Skipping." echo "There is no device in ${etc_crypttab}. Skipping."
return 0 return 0
fi fi
umask 0022 umask 0022
sshcs_check_keys sshcs_check_keys
add_checked_modules "/drivers/net/" # Note: parts of this script (modules/binaries/files added) are the same than
# Note: parts of this script (modules/binaries added) are the same than the # other install scripts (/usr/lib/initcpio/install/):
# 'encrypt' install script (/usr/lib/initcpio/install/encrypt) which is the # - 'encrypt': nominal support of encrypted volumes at boot time
# nominal one to deal with encrypted volumes at boot time. # - 'net': network tools
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 ## Modules
add_binary "cryptsetup" # (from 'encrypt')
add_binary "dmsetup" add_module 'dm-crypt'
add_binary "dropbear" add_module 'dm-integrity'
add_binary "ip" if [[ $CRYPTO_MODULES ]]; then
add_binary "/usr/lib/initcpio/ipconfig" "/sbin/ipconfig" local mod
for mod in $CRYPTO_MODULES; do
# Our hook files add_module "$mod"
[ -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"
for keytype in "${dropbear_key_types[@]}"; do
add_file "${dropbear_keyfile_prefix}${keytype}${dropbear_keyfile_suffix}"
done done
else
add_all_modules '/crypto/'
fi
# cryptsetup-related files # (from 'net')
add_file "${etc_crypttab}" add_checked_modules '/drivers/net/'
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"
# 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 ## 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'
# (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
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
# crypt partitions
add_file "${etc_crypttab}"
add_runscript
} }
help() { help() {
cat <<EOF cat <<EOF
This hook allows for LUKS encrypted devices to be unlocked either locally This hook allows for LUKS encrypted devices to be unlocked either locally
(boot console) or remotely over SSH. (boot console) or remotely over SSH.
@@ -111,15 +129,8 @@ 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/initcpio/sshcs_env' (file is sourced in Some options can be set in '/etc/initcpio/sshcs_env'.
initrd shell): See the README for more details.
* '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_ecdsa_host_key' and 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 'dropbear_ed25519_host_key' in '/etc/dropbear' folder) is imported from OpenSSH