Compare commits
17 Commits
Author | SHA1 | Date |
---|---|---|
![]() |
22da78cdef | |
![]() |
d34b39b77f | |
![]() |
8f92d149eb | |
![]() |
f20941d376 | |
![]() |
a2924457d3 | |
![]() |
c3cafcf6cd | |
![]() |
b3e9382f08 | |
![]() |
8ebd239c7a | |
![]() |
bc04382857 | |
![]() |
e47043f3a1 | |
![]() |
4c1a7741d6 | |
![]() |
6167cbc9cd | |
![]() |
a13fecf645 | |
![]() |
d94d257cf6 | |
![]() |
e5ee05f382 | |
![]() |
cf6ccb2d23 | |
![]() |
724d6a6bf0 |
98
ChangeLog
98
ChangeLog
|
@ -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>
|
||||
|
||||
* 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.
|
||||
See: 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.
|
||||
|
|
15
PKGBUILD
15
PKGBUILD
|
@ -1,20 +1,21 @@
|
|||
# Maintainer: Julien Coloos <julien.coloos [at] gmail [dot] com>
|
||||
pkgname=initrd-ssh-cryptsetup
|
||||
pkgver=0.2
|
||||
pkgver=1.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')
|
||||
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=('33295d11216cb96a5b30f035add123d136fac38decd393d677f1c02b9ad22379'
|
||||
'b84978b3c2ef32208c2b104ee2d3ce8aaec26da0bd4e9e1c83942f373bbf6285')
|
||||
|
||||
package() {
|
||||
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/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-tools" "$pkgdir/usr/lib/initcpio/hooks/ssh-cryptsetup-tools"
|
||||
}
|
||||
|
||||
|
|
74
README.md
74
README.md
|
@ -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.
|
||||
The code was reworked from [dropbear_initrd_encrypt](https://aur.archlinux.org/packages/dropbear_initrd_encrypt/).
|
||||
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.
|
||||
|
||||
|
||||
## 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 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
|
||||
- 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
|
||||
* `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:
|
||||
|
||||
sshcs_opt_timeout_ipconfig=30
|
||||
sshcs_opt_listen=2222
|
||||
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
|
||||
|
|
|
@ -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}"
|
||||
|
|
|
@ -1,270 +1,324 @@
|
|||
#!/usr/bin/ash
|
||||
|
||||
. "/usr/local/bin/ssh-cryptsetup-tools"
|
||||
|
||||
sshcs_net_start() {
|
||||
# we must have an 'ip' setting, and a device in it
|
||||
[ -z "${ip}" ] && [ -n "${nfsaddrs}" ] && ip="${nfsaddrs}"
|
||||
[ -z "${ip}" ] && return 1
|
||||
local iparg net_address ipconfig_out net_netmask net_gateway net_dns0 net_dns1
|
||||
|
||||
net_device=$(echo ${ip} | cut -d: -f6)
|
||||
[ -z "${net_device}" ] && 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
|
||||
}
|
||||
|
||||
# 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
|
||||
net_device=$(echo ${ip} | cut -d: -f6)
|
||||
[ -z "${net_device}" ] && {
|
||||
dbg "No network device to setup"
|
||||
return 1
|
||||
}
|
||||
|
||||
line="$(echo "${line}" | sed -e 's/ :/:/g;s/: /=/g')"
|
||||
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
|
||||
|
||||
for iparg in ${line}; do
|
||||
case "${iparg}" in
|
||||
address=*|netmask=*|gateway=*|dns0=*|dns1=*)
|
||||
echo "net_${iparg}" >> "${net_env}"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
# 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}"
|
||||
|
||||
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="$(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}" ]
|
||||
}
|
||||
|
||||
sshcs_trapped_timeout() {
|
||||
err "Timeout reached! Powering off."
|
||||
poweroff -f
|
||||
exit
|
||||
}
|
||||
|
||||
sshcs_trap_timeout() {
|
||||
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
|
||||
}
|
||||
|
||||
sshcs_untrap_timeout() {
|
||||
[ -z "${pid_timeout}" ] && return 0
|
||||
kill ${pid_timeout}
|
||||
trap - SIGALRM
|
||||
msg "Timeout cleared."
|
||||
}
|
||||
|
||||
sshcs_dropbear_unlock() {
|
||||
local timeout_poweroff_min=120
|
||||
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
|
||||
|
||||
# /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"
|
||||
|
||||
# root login script
|
||||
cat <<EOF > "${dropbear_login_shell}"
|
||||
#!/usr/bin/ash
|
||||
|
||||
. "/init_functions"
|
||||
|
||||
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 "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"
|
||||
|
||||
[ -e "${dropbear_env}" ] && . "${dropbear_env}"
|
||||
[ -n "${sshcs_opt_listen}" ] && sshcs_opt_listen="-p ${sshcs_opt_listen}"
|
||||
[ -z "${sshcs_opt_timeout_poweroff}" ] && sshcs_opt_timeout_poweroff=${timeout_poweroff_min}
|
||||
[ ${sshcs_opt_timeout_poweroff} -ge 0 ] && [ ${sshcs_opt_timeout_poweroff} -lt ${timeout_poweroff_min} ] && sshcs_opt_timeout_poweroff=${timeout_poweroff_min}
|
||||
|
||||
|
||||
msg "Starting dropbear ..."
|
||||
dropbear -Emsgjk -P "${path_dropbear_pid}" ${sshcs_opt_listen}
|
||||
|
||||
sshcs_trap_timeout
|
||||
|
||||
# actual script (shared with SSH login) unlocking encrypted devices
|
||||
. "${dropbear_cryptsetup_script}"
|
||||
|
||||
sshcs_untrap_timeout
|
||||
|
||||
# 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
|
||||
[ -n "${net_address}" ]
|
||||
}
|
||||
|
||||
sshcs_net_done() {
|
||||
# we are done with the network
|
||||
if [ -n "${net_device}" ]; then
|
||||
ip addr flush dev "${net_device}"
|
||||
ip link set dev "${net_device}" down
|
||||
fi
|
||||
# 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
|
||||
}
|
||||
|
||||
sshcs_trap_timeout() {
|
||||
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"
|
||||
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
|
||||
# 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
|
||||
msg "Timeout cleared."
|
||||
}
|
||||
|
||||
sshcs_shell_run() {
|
||||
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 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
|
||||
|
||||
if [ ${sshcs_opt_use_shell} -eq 0 ]; then
|
||||
sshcs_shell_script=${sshcs_cryptsetup_script}
|
||||
else
|
||||
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
|
||||
|
||||
# /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"
|
||||
touch "/var/log/lastlog"
|
||||
|
||||
msg "Starting dropbear ..."
|
||||
dropbear -Esgjk -P "${path_dropbear_pid}" ${sshcs_opt_listen}
|
||||
|
||||
# Actual unlocking shell
|
||||
sshcs_shell_run
|
||||
}
|
||||
|
||||
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=}"
|
||||
local cryptdev_orig cryptopt cryptargs
|
||||
|
||||
# get crypt options
|
||||
cryptargs=
|
||||
for cryptopt in ${cryptoptions//,/ }; do
|
||||
case ${cryptopt} in
|
||||
allow-discards)
|
||||
cryptargs="${cryptargs} --allow-discards"
|
||||
;;
|
||||
# ensure there is a device (handle 'UUID=' format)
|
||||
[ -z "${cryptdev}" ] && return 0
|
||||
[ "${cryptdev#UUID=}" != "${cryptdev}" ] && cryptdev="/dev/disk/by-uuid/${cryptdev#UUID=}"
|
||||
|
||||
luks)
|
||||
;;
|
||||
# get crypt options
|
||||
cryptargs=
|
||||
for cryptopt in ${cryptoptions//,/ }; do
|
||||
case ${cryptopt} in
|
||||
discard)
|
||||
cryptargs="${cryptargs} --allow-discards"
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Device ${cryptdev} encryption option '${cryptopt}' not known, ignoring."
|
||||
;;
|
||||
esac
|
||||
done
|
||||
luks)
|
||||
;;
|
||||
|
||||
# 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
|
||||
*)
|
||||
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
|
||||
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 "${dropbear_cryptsetup_script}" ] || cat <<EOF > "${dropbear_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 "Within 5s press 'P' to poweroff, 'R' to reboot or any other key to retry. " res
|
||||
echo ""
|
||||
[ "${res}" == "P" ] && poweroff -f
|
||||
[ "${res}" == "R" ] && reboot -f
|
||||
}
|
||||
|
||||
try_unlock() {
|
||||
EOF
|
||||
|
||||
cat <<EOF >> "${dropbear_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
|
||||
cat <<EOF >> "${sshcs_cryptsetup_script}"
|
||||
# loop until device is available
|
||||
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 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
|
||||
done
|
||||
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
|
||||
}
|
||||
|
||||
sshcs_cryptpart_setup() {
|
||||
local cryptdev crypttype cryptname cryptpass cryptoptions
|
||||
|
||||
# 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
|
||||
|
||||
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 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 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
|
||||
|
||||
# sanity check: crypttab should be present
|
||||
[ ! -e "${etc_crypttab}" ] && return 0
|
||||
# Note: options were loaded already
|
||||
|
||||
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
|
||||
# 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) &
|
||||
|
||||
# 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
|
||||
modprobe -a -q dm-crypt >/dev/null 2>&1
|
||||
[ "${quiet}" = "y" ] && CSQUIET=">/dev/null"
|
||||
|
||||
# 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
|
||||
umask 0022
|
||||
|
||||
sshcs_cryptpart_process
|
||||
done < "${etc_crypttab}"
|
||||
# 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."
|
||||
return 0
|
||||
fi
|
||||
|
||||
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
|
||||
# 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
|
||||
fi
|
||||
|
||||
# time to unlock (through console or dropbear)
|
||||
sshcs_dropbear_unlock
|
||||
# stop the network before going on in boot sequence
|
||||
sshcs_net_done
|
||||
# time to unlock (through console or dropbear)
|
||||
sshcs_dropbear_run
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -1,99 +1,128 @@
|
|||
#!/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
|
||||
# Note: parts of this script (modules/binaries/files added) are the same than
|
||||
# other install scripts (/usr/lib/initcpio/install/):
|
||||
# - 'encryp': nominal support of encrypted volumes at boot time
|
||||
# - 'net': network tools
|
||||
|
||||
# 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"
|
||||
## Modules
|
||||
# (from 'encrypt')
|
||||
add_module 'dm-crypt'
|
||||
add_module 'dm-integrity'
|
||||
if [[ $CRYPTO_MODULES ]]; then
|
||||
local mod
|
||||
for mod in $CRYPTO_MODULES; do
|
||||
add_module "$mod"
|
||||
done
|
||||
else
|
||||
add_all_modules '/crypto/'
|
||||
fi
|
||||
|
||||
# auth-related files
|
||||
add_file "/lib/libnss_files.so"
|
||||
|
||||
# SSH-related files
|
||||
add_file "${dropbear_authorized_keys}" "/root/.ssh/authorized_keys"
|
||||
[ -e "${dropbear_env}" ] && add_file "${dropbear_env}"
|
||||
add_file "/etc/dropbear/dropbear_rsa_host_key"
|
||||
add_file "/etc/dropbear/dropbear_dss_host_key"
|
||||
add_file "/etc/dropbear/dropbear_ecdsa_host_key"
|
||||
|
||||
# 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"
|
||||
# (from 'net')
|
||||
add_checked_modules '/drivers/net/'
|
||||
|
||||
|
||||
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' \
|
||||
'/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
|
||||
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() {
|
||||
cat <<EOF
|
||||
cat <<EOF
|
||||
This hook allows for LUKS encrypted devices to be unlocked either locally
|
||||
(boot console) or remotely over SSH.
|
||||
|
||||
|
@ -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'.
|
||||
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_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
|
||||
* '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
|
||||
- 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
|
||||
* '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
|
||||
'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
|
||||
|
|
Loading…
Reference in New Issue