mirror of
				https://github.com/suiryc/archlinux-initrd-ssh-cryptsetup.git
				synced 2025-11-04 02:02:31 +03:00 
			
		
		
		
	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
This commit is contained in:
		@@ -1,3 +1,10 @@
 | 
			
		||||
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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								PKGBUILD
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								PKGBUILD
									
									
									
									
									
								
							@@ -1,20 +1,21 @@
 | 
			
		||||
# Maintainer: Julien Coloos <julien.coloos [at] gmail [dot] com>
 | 
			
		||||
pkgname=initrd-ssh-cryptsetup
 | 
			
		||||
pkgver=0.9
 | 
			
		||||
pkgrel=2
 | 
			
		||||
pkgdesc="Allows for LUKS-encrypted devices to be unlocked remotely over SSH"
 | 
			
		||||
pkgver=1.0
 | 
			
		||||
pkgrel=1
 | 
			
		||||
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")
 | 
			
		||||
sha256sums=('c3fa91fc8ba2228b3492d3709231918c8015cc3da49f516c3eacea5c0217536c'
 | 
			
		||||
sha256sums=('de6ef287ecfd57614835fec1fcaa01eb3a7f999d42a749e20b6747671320508f'
 | 
			
		||||
            '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/hooks/ssh-cryptsetup-tools" "$pkgdir/usr/lib/initcpio/hooks/ssh-cryptsetup-tools"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										26
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								README.md
									
									
									
									
									
								
							@@ -1,4 +1,4 @@
 | 
			
		||||
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.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -37,33 +37,43 @@ As explained upon installation, the following things need to be done:
 | 
			
		||||
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_debug`: whether to be more verbose about ongoing actions
 | 
			
		||||
      - default: 0
 | 
			
		||||
      - 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 seconds
 | 
			
		||||
      - default: `10`
 | 
			
		||||
   * `sshcs_opt_listen`: SSH listening port
 | 
			
		||||
      - default: 22
 | 
			
		||||
      - default: `22`
 | 
			
		||||
   * `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
 | 
			
		||||
   * `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
 | 
			
		||||
   * archive the `src` folder in `$pkgname-$pkgver.tar.xz` file; e.g.: `tar -cJf initrd-ssh-cryptsetup-0.9.tar.xz src`
 | 
			
		||||
   * 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 `pkgver` if `src` was modified, or `pkgrel` if building files were modified
 | 
			
		||||
   * 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,23 +1,10 @@
 | 
			
		||||
#!/usr/bin/ash
 | 
			
		||||
 | 
			
		||||
dbg () {
 | 
			
		||||
    [ ${sshcs_opt_debug} != 0 ] && echo "$@"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sshcs_env_load() {
 | 
			
		||||
    local debug_default=0
 | 
			
		||||
    local timeout_ipconfig_default=10
 | 
			
		||||
    local timeout_poweroff_min=120
 | 
			
		||||
 | 
			
		||||
    [ -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}
 | 
			
		||||
}
 | 
			
		||||
. "/usr/local/bin/ssh-cryptsetup-tools"
 | 
			
		||||
 | 
			
		||||
sshcs_net_start() {
 | 
			
		||||
  local iparg net_address ipconfig_out net_netmask net_gateway net_dns0 net_dns1
 | 
			
		||||
 | 
			
		||||
  # we must have an 'ip' setting, and a device in it
 | 
			
		||||
  [ -z "${ip}" ] && [ -n "${nfsaddrs}" ] && ip="${nfsaddrs}"
 | 
			
		||||
  [ -z "${ip}" ] && {
 | 
			
		||||
@@ -31,6 +18,11 @@ sshcs_net_start() {
 | 
			
		||||
    return 1
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if [ "${sshcs_opt_net_wol:-d}" != "d" ]; then
 | 
			
		||||
    dbg "Setting network device=${net_device} wol=${sshcs_opt_net_wol}"
 | 
			
		||||
    ethtool -s "${net_device}" wol "${sshcs_opt_net_wol}"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # Setup network and save some values
 | 
			
		||||
  # Note: some useful redirection means ('< <(...)' and '<<< "$(...)"') are
 | 
			
		||||
  # not supported in the available shell. So we have to write code in a
 | 
			
		||||
@@ -93,7 +85,6 @@ sshcs_trap_timeout() {
 | 
			
		||||
    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}
 | 
			
		||||
@@ -107,21 +98,25 @@ sshcs_trap_timeout() {
 | 
			
		||||
 | 
			
		||||
sshcs_untrap_timeout() {
 | 
			
		||||
  [ -z "${pid_timeout}" ] && return 0
 | 
			
		||||
    kill ${pid_timeout}
 | 
			
		||||
  # Notes:
 | 
			
		||||
  # If there was a running SSH shell, it may also try to kill it.
 | 
			
		||||
  # This only kills the spawned subshell, leaving the 'sleep' command still
 | 
			
		||||
  # running until done (which is not an issue).
 | 
			
		||||
  proc_parse_stat ${pid_timeout} && kill ${pid_timeout}
 | 
			
		||||
  pid_timeout=
 | 
			
		||||
  trap - SIGALRM
 | 
			
		||||
  msg "Timeout cleared."
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sshcs_unlock() {
 | 
			
		||||
sshcs_shell_run() {
 | 
			
		||||
  sshcs_trap_timeout
 | 
			
		||||
 | 
			
		||||
    # actual script (shared with SSH login) unlocking encrypted devices
 | 
			
		||||
    . "${sshcs_cryptsetup_script}"
 | 
			
		||||
 | 
			
		||||
    sshcs_untrap_timeout
 | 
			
		||||
  # actual script (shared with SSH login) with which we can unlock devices
 | 
			
		||||
  sshcs_unlocked_test=0
 | 
			
		||||
  . "${sshcs_shell_script}"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sshcs_dropbear_unlock() {
 | 
			
		||||
sshcs_dropbear_run() {
 | 
			
		||||
  local pid_timeout=
 | 
			
		||||
  local dev_pts_mounted=0
 | 
			
		||||
  local listen=
 | 
			
		||||
@@ -133,34 +128,29 @@ sshcs_dropbear_unlock() {
 | 
			
		||||
    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}"
 | 
			
		||||
  if [ ${sshcs_opt_use_shell} -eq 0 ]; then
 | 
			
		||||
    sshcs_shell_script=${sshcs_cryptsetup_script}
 | 
			
		||||
  else
 | 
			
		||||
    cat <<EOF > "${sshcs_shell_script}"
 | 
			
		||||
#!/usr/bin/ash
 | 
			
		||||
 | 
			
		||||
. "/init_functions"
 | 
			
		||||
 | 
			
		||||
if [ ! -f "${sshcs_cryptsetup_script}" ]; then
 | 
			
		||||
    err "No cryptsetup script present! Please retry."
 | 
			
		||||
    exit 0
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if [ -c "/dev/mapper/control" ]; then
 | 
			
		||||
    CSQUIET=
 | 
			
		||||
    . "${sshcs_cryptsetup_script}"
 | 
			
		||||
. "/usr/local/bin/ssh-cryptsetup-tools"
 | 
			
		||||
 | 
			
		||||
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 ""
 | 
			
		||||
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 "${dropbear_login_shell}"
 | 
			
		||||
    chmod a+x "${sshcs_shell_script}"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # /etc/passwd file for the root user
 | 
			
		||||
  echo "root:x:0:0:root:/root:${sshcs_shell_script}" > "/etc/passwd"
 | 
			
		||||
  echo "${sshcs_shell_script}" > "/etc/shells"
 | 
			
		||||
 | 
			
		||||
  [ ! -d "/var/log" ] && mkdir -p "/var/log"
 | 
			
		||||
  touch "/var/log/lastlog"
 | 
			
		||||
@@ -168,25 +158,13 @@ EOF
 | 
			
		||||
  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
 | 
			
		||||
  # Actual unlocking shell
 | 
			
		||||
  sshcs_shell_run
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sshcs_cryptpart_process() {
 | 
			
		||||
  local cryptdev_orig cryptopt cryptargs
 | 
			
		||||
 | 
			
		||||
  # ensure there is a device (handle 'UUID=' format)
 | 
			
		||||
  [ -z "${cryptdev}" ] && return 0
 | 
			
		||||
  [ "${cryptdev#UUID=}" != "${cryptdev}" ] && cryptdev="/dev/disk/by-uuid/${cryptdev#UUID=}"
 | 
			
		||||
@@ -215,23 +193,30 @@ sshcs_cryptpart_process() {
 | 
			
		||||
      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}"
 | 
			
		||||
      [ -s "${sshcs_cryptsetup_script}" ] || cat <<'EOF' > "${sshcs_cryptsetup_script}"
 | 
			
		||||
#!/usr/bin/ash
 | 
			
		||||
 | 
			
		||||
. "/usr/local/bin/ssh-cryptsetup-tools"
 | 
			
		||||
 | 
			
		||||
cycle_or_retry() {
 | 
			
		||||
  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 ""
 | 
			
		||||
    if [ "\${res}" = "P" ]; then
 | 
			
		||||
        poweroff -f
 | 
			
		||||
    elif [ "\${res}" = "R" ]; then
 | 
			
		||||
        reboot -f
 | 
			
		||||
    fi
 | 
			
		||||
  [ "${res}" == "P" ] && poweroff -f
 | 
			
		||||
  [ "${res}" == "R" ] && reboot -f
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
try_unlock() {
 | 
			
		||||
EOF
 | 
			
		||||
 | 
			
		||||
      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
 | 
			
		||||
@@ -253,29 +238,8 @@ EOF
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
run_hook() {
 | 
			
		||||
    local etc_crypttab="/etc/crypttab"
 | 
			
		||||
    local sshcs_env="/etc/initcpio/sshcs_env"
 | 
			
		||||
    local path_dropbear_pid="/.dropbear.pid"
 | 
			
		||||
    local dropbear_login_shell="/.cryptsetup_shell.sh"
 | 
			
		||||
    local sshcs_cryptsetup_script="/.cryptsetup_script.sh"
 | 
			
		||||
    local net_env="/.net_env.sh"
 | 
			
		||||
    local line iparg net_address net_device ipconfig_out net_netmask net_gateway net_dns0 net_dns1
 | 
			
		||||
    local cryptdev cryptdev_orig crypttype cryptname cryptpass cryptoptions cryptopt cryptargs CSQUIET
 | 
			
		||||
 | 
			
		||||
    # Load our options
 | 
			
		||||
    sshcs_env_load
 | 
			
		||||
 | 
			
		||||
    # sanity check: crypttab should be present
 | 
			
		||||
    [ ! -e "${etc_crypttab}" ] && {
 | 
			
		||||
        dbg "No crypttab configuration to process"
 | 
			
		||||
        return 0
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    modprobe -a -q dm-crypt >/dev/null 2>&1
 | 
			
		||||
    [ "${quiet}" = "y" ] && CSQUIET=">/dev/null"
 | 
			
		||||
 | 
			
		||||
    umask 0022
 | 
			
		||||
sshcs_cryptpart_setup() {
 | 
			
		||||
  local cryptdev crypttype cryptname cryptpass cryptoptions
 | 
			
		||||
 | 
			
		||||
  # check encrypted devices to handle
 | 
			
		||||
  cryptdev=
 | 
			
		||||
@@ -289,6 +253,59 @@ run_hook() {
 | 
			
		||||
    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 path_dropbear_pid="/.dropbear.pid"
 | 
			
		||||
  local sshcs_shell_script="/.sshcs_shell.sh"
 | 
			
		||||
  local net_env="/.sshcs_net_env.sh"
 | 
			
		||||
  local line net_device
 | 
			
		||||
  local CSQUIET
 | 
			
		||||
 | 
			
		||||
  # Note: options were loaded already
 | 
			
		||||
 | 
			
		||||
  # sanity check: crypttab should be present
 | 
			
		||||
  [ ! -e "${etc_crypttab}" ] && {
 | 
			
		||||
    dbg "No crypttab configuration to process"
 | 
			
		||||
    return 0
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  # Initialize random generator ASAP.
 | 
			
		||||
  # May delay first SSH login by a few seconds otherwise.
 | 
			
		||||
  (dd if=/dev/urandom of=/dev/null bs=4 count=1 status=none > /dev/null 2>&1) &
 | 
			
		||||
  (dd if=/dev/random of=/dev/null bs=4 count=1 status=none > /dev/null 2>&1) &
 | 
			
		||||
 | 
			
		||||
  modprobe -a -q dm-crypt >/dev/null 2>&1
 | 
			
		||||
  [ "${quiet}" = "y" ] && CSQUIET=">/dev/null"
 | 
			
		||||
 | 
			
		||||
  umask 0022
 | 
			
		||||
 | 
			
		||||
  # Setup script used to unlock device either in console or SSH
 | 
			
		||||
  sshcs_cryptpart_setup
 | 
			
		||||
  if [ ! -e "${sshcs_cryptsetup_script}" ]; then
 | 
			
		||||
    err "No encrypted device found! Skipping crypt remote unlocking."
 | 
			
		||||
    return 0
 | 
			
		||||
@@ -298,14 +315,10 @@ run_hook() {
 | 
			
		||||
  if ! sshcs_net_start; then
 | 
			
		||||
    err "Net interface not available! Skipping crypt remote unlocking."
 | 
			
		||||
    # We still allow to unlock locally with timeout
 | 
			
		||||
        sshcs_unlock
 | 
			
		||||
        # stop the network if possible
 | 
			
		||||
        sshcs_net_done
 | 
			
		||||
    sshcs_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
 | 
			
		||||
  sshcs_dropbear_run
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										188
									
								
								src/hooks/ssh-cryptsetup-tools
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										188
									
								
								src/hooks/ssh-cryptsetup-tools
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,188 @@
 | 
			
		||||
#!/usr/bin/ash
 | 
			
		||||
 | 
			
		||||
. "/init_functions"
 | 
			
		||||
 | 
			
		||||
dbg () {
 | 
			
		||||
  [ ${sshcs_opt_debug} != 0 ] && echo "$@"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sshcs_env_load() {
 | 
			
		||||
  local sshcs_env="/etc/initcpio/sshcs_env"
 | 
			
		||||
 | 
			
		||||
  local debug_default=0
 | 
			
		||||
  local net_wol_default=g
 | 
			
		||||
  local timeout_ipconfig_default=10
 | 
			
		||||
  local timeout_poweroff_min=120
 | 
			
		||||
  local use_shell_default=0
 | 
			
		||||
 | 
			
		||||
  [ ${sshcs_env_loaded:-0} -eq 1 ] && return
 | 
			
		||||
  [ -e "${sshcs_env}" ] && . "${sshcs_env}"
 | 
			
		||||
  sshcs_env_loaded=1
 | 
			
		||||
  [ -z "${sshcs_opt_debug}" ] && sshcs_opt_debug=${debug_default}
 | 
			
		||||
  [ -z "${sshcs_opt_net_wol}" ] && sshcs_opt_net_wol=${net_wol_default}
 | 
			
		||||
  [ -z "${sshcs_opt_timeout_ipconfig}" ] && sshcs_opt_timeout_ipconfig=${timeout_ipconfig_default}
 | 
			
		||||
  [ -n "${sshcs_opt_listen}" ] && sshcs_opt_listen="-p ${sshcs_opt_listen}"
 | 
			
		||||
  [ -z "${sshcs_opt_timeout_poweroff}" ] && sshcs_opt_timeout_poweroff=${timeout_poweroff_min}
 | 
			
		||||
  [ -z "${sshcs_opt_use_shell}" ] && sshcs_opt_use_shell=${use_shell_default}
 | 
			
		||||
  [ ${sshcs_opt_timeout_poweroff} -ge 0 ] && [ ${sshcs_opt_timeout_poweroff} -lt ${timeout_poweroff_min} ] && sshcs_opt_timeout_poweroff=${timeout_poweroff_min}
 | 
			
		||||
 | 
			
		||||
  sshcs_cryptsetup_script="/.sshcs_cryptsetup_script.sh"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
proc_parse_stat() {
 | 
			
		||||
  local unused
 | 
			
		||||
 | 
			
		||||
  pid=$1
 | 
			
		||||
  cmd=
 | 
			
		||||
  ppid=
 | 
			
		||||
  [ ! -e /proc/${pid}/stat ] && return 1
 | 
			
		||||
  read unused cmd unused ppid unused < /proc/${pid}/stat
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
proc_find_parent_cmd() {
 | 
			
		||||
  pid=$1
 | 
			
		||||
  proc_parse_stat ${pid} || return 1
 | 
			
		||||
  while [ ${ppid} -gt 1 ]
 | 
			
		||||
  do
 | 
			
		||||
    proc_parse_stat ${ppid} || return 1
 | 
			
		||||
    if [ "${cmd}" == "($2)" ]; then
 | 
			
		||||
      ppid=${pid}
 | 
			
		||||
      pid=$1
 | 
			
		||||
      return 0
 | 
			
		||||
    fi
 | 
			
		||||
    pid=${ppid}
 | 
			
		||||
  done
 | 
			
		||||
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
proc_is_console() {
 | 
			
		||||
  if [ -z "${is_console:-}" ]; then
 | 
			
		||||
    # We are in console if we were not forked from dropbear.
 | 
			
		||||
    is_console=1
 | 
			
		||||
    proc_find_parent_cmd $$ "dropbear" && is_console=0
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  [ "${is_console}" -eq 1 ]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sshcs_cleanup() {
 | 
			
		||||
  local pgrep_output
 | 
			
		||||
 | 
			
		||||
  # Reminders:
 | 
			
		||||
  # We are called when devices have been unlocked.
 | 
			
		||||
  #
 | 
			
		||||
  # We are only called as part of the main shell (whether on console - the init
 | 
			
		||||
  # script - or through SSH - as the user login shell), and once we return our
 | 
			
		||||
  # parent shell will end.
 | 
			
		||||
  #
 | 
			
		||||
  # The unlocking script does 'killall cryptsetup' after each successful unlock,
 | 
			
		||||
  # which is used to wakeup any other running unlocking script.
 | 
			
		||||
  # Thus as long as all devices have been unlocked, we don't expect any script
 | 
			
		||||
  # to be stuck on 'cryptsetup' calls.
 | 
			
		||||
 | 
			
		||||
  if proc_is_console; then
 | 
			
		||||
    # We are in the console.
 | 
			
		||||
    # It is time to properly end the processes we started and files we created.
 | 
			
		||||
    # When using a shell - instead of directly calling the unlocking script -
 | 
			
		||||
    # we also need to signal any SSH shell so that it is properly cleaned too.
 | 
			
		||||
 | 
			
		||||
    # cleanup dropbear
 | 
			
		||||
    if [ -f "${path_dropbear_pid}" ]; then
 | 
			
		||||
      msg "Stopping dropbear ..."
 | 
			
		||||
      kill $(cat "${path_dropbear_pid}")
 | 
			
		||||
      rm -f "${path_dropbear_pid}"
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if [ ${sshcs_opt_use_shell} -eq 1 ]; then
 | 
			
		||||
      # Find and kill all shells spawned by SSH.
 | 
			
		||||
      # This is necessary to properly terminate both these shells and the spawned
 | 
			
		||||
      # SSH processes.
 | 
			
		||||
      # Reminder: "... | ..." does fork a subshell
 | 
			
		||||
      dbg "Searching SSH shells ..."
 | 
			
		||||
      pgrep_output=$(pgrep /usr/bin/ash)
 | 
			
		||||
      pgrep_output=$(echo "${pgrep_output}" | grep -E -v "^(|1|$$)$")
 | 
			
		||||
      echo "${pgrep_output}" | while read pid; do
 | 
			
		||||
        proc_parse_stat ${pid} || continue
 | 
			
		||||
        proc_find_parent_cmd ${pid} "dropbear" || continue
 | 
			
		||||
        dbg "Killing SSH shell pid=${pid}"
 | 
			
		||||
        kill -SIGHUP ${pid}
 | 
			
		||||
      done
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    # cleanup /dev/pts if necessary
 | 
			
		||||
    if [ ${dev_pts_mounted} -ne 0 ]; then
 | 
			
		||||
      umount "/dev/pts"
 | 
			
		||||
      rm -R "/dev/pts"
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    # stop the network before going on in boot sequence
 | 
			
		||||
    sshcs_net_done
 | 
			
		||||
 | 
			
		||||
    rm -f "${sshcs_cryptsetup_script}" "${sshcs_shell_script}" "/etc/passwd" "/etc/shells" "/var/log/lastlog"
 | 
			
		||||
  elif [ ${sshcs_opt_use_shell} -eq 1 ]; then
 | 
			
		||||
    # We are in a SSH shell session.
 | 
			
		||||
 | 
			
		||||
    # Find and kill console shell.
 | 
			
		||||
    # This is necessary so that our script launched from the init process can
 | 
			
		||||
    # finally check that devices have been properly unlocked, properly end and
 | 
			
		||||
    # let the init process end booting.
 | 
			
		||||
    # Note: as a side effect, this will also kill the shell that was forked to
 | 
			
		||||
    # trigger a timeout, which is fine (we want to kill it, either from here or
 | 
			
		||||
    # from the init shell).
 | 
			
		||||
    dbg "Searching console shells ..."
 | 
			
		||||
    pgrep_output=$(pgrep /usr/bin/ash)
 | 
			
		||||
    pgrep_output=$(echo "${pgrep_output}" | grep -E -v "^(|1|$$)$")
 | 
			
		||||
    echo "${pgrep_output}" | while read pid; do
 | 
			
		||||
      proc_find_parent_cmd ${pid} "dropbear" && continue
 | 
			
		||||
      dbg "Killing console shell pid=${pid}"
 | 
			
		||||
      kill -SIGHUP ${pid}
 | 
			
		||||
    done
 | 
			
		||||
  fi
 | 
			
		||||
  # else: when in SSH shell script, we have nothing else to do other than exit.
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sshcs_check_done() {
 | 
			
		||||
  # Whether we are called from the main script: that is whether the shell will
 | 
			
		||||
  # end when we return.
 | 
			
		||||
  local finalize=$1
 | 
			
		||||
 | 
			
		||||
  # This is always the main script when not using shell
 | 
			
		||||
  [ ${sshcs_opt_use_shell} -eq 0 ] && finalize=1
 | 
			
		||||
 | 
			
		||||
  # Reset timeout when applicable: only possible from init script.
 | 
			
		||||
  proc_is_console && type sshcs_untrap_timeout > /dev/null 2>&1 && sshcs_untrap_timeout
 | 
			
		||||
 | 
			
		||||
  # Check devices are unlocked.
 | 
			
		||||
  sshcs_unlocked_test=1
 | 
			
		||||
  sshcs_unlocked=1
 | 
			
		||||
  . "${sshcs_cryptsetup_script}"
 | 
			
		||||
  if [ ${sshcs_unlocked} -ne 1 ]; then
 | 
			
		||||
    echo ""
 | 
			
		||||
    # When finalizing in console, power off
 | 
			
		||||
    if [ ${finalize} -eq 1 ] &&  proc_is_console; then
 | 
			
		||||
      err "Devices are still locked! Powering off."
 | 
			
		||||
      poweroff -f
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    # When in shell or SSH, let user try again
 | 
			
		||||
    err "Devices are still locked! Please retry."
 | 
			
		||||
    return
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ ${finalize} -eq 0 ]; then
 | 
			
		||||
    # Kill our parent (the interactive shell); the script that launched it will
 | 
			
		||||
    # do finalization.
 | 
			
		||||
    proc_parse_stat $$
 | 
			
		||||
    kill -SIGHUP ${ppid}
 | 
			
		||||
    exit 0
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  echo ""
 | 
			
		||||
  echo "cryptsetup succeeded! Boot sequence should go on."
 | 
			
		||||
  proc_is_console || echo "Please wait and reconnect to nominal SSH service."
 | 
			
		||||
 | 
			
		||||
  sshcs_cleanup
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sshcs_env_load
 | 
			
		||||
@@ -72,10 +72,14 @@ build() {
 | 
			
		||||
  add_binary "dmsetup"
 | 
			
		||||
  add_binary "dropbear"
 | 
			
		||||
  add_binary "ip"
 | 
			
		||||
    add_binary "/usr/lib/initcpio/ipconfig" "/sbin/ipconfig"
 | 
			
		||||
  add_binary "/usr/lib/initcpio/ipconfig" "/bin/ipconfig"
 | 
			
		||||
  add_binary "ethtool"
 | 
			
		||||
 | 
			
		||||
  # Our hook files
 | 
			
		||||
  [ -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"
 | 
			
		||||
 | 
			
		||||
  # auth-related files
 | 
			
		||||
  add_file "/lib/libnss_files.so"
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user