summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Deutschmann <whissi@gentoo.org>2019-07-14 11:11:09 +0200
committerThomas Deutschmann <whissi@gentoo.org>2019-07-14 13:58:15 +0200
commit11eff5eb7ad4330c2688ff4795ba33bbf6efcc47 (patch)
treef50a9947ae3a0ebef542521cdd3de401fe43d03a
parentAdd genkernel worker module "dropbear" (diff)
downloadgenkernel-11eff5eb7ad4330c2688ff4795ba33bbf6efcc47.tar.gz
genkernel-11eff5eb7ad4330c2688ff4795ba33bbf6efcc47.tar.bz2
genkernel-11eff5eb7ad4330c2688ff4795ba33bbf6efcc47.zip
Rework --ssh support
- To enable sshd in initramfs user MUST now set "dosshd" kernel command-line parameter. - "gk.sshd.wait" kernel command-line parameter was added to interrupt boot process for X seconds to allow for remote login (can be used like an remote rescue shell). - For remote unlock of LUKS-encrypted root or swap device, user can still send unencrypted keyfile via SSH like $ cat ~/root.unencrypted.key | ssh root@<remote-host> -C post root or user can now just SSH into the remote host and call "unlock-luks" like remote rescueshell ~ # unlock-luks root to get a cryptsetup prompt. NOTE: When manually unlocking the encrypted LUKS device, user must call "resume-boot" afterwards to resume booting. - "--ssh-authorized-keys-file" parameter added which can be used to specify a different file than default "/etc/dropbear/authorized_keys" file. - "--ssh-host-keys" parameter added to control if in initramfs embedded sshd should create its own pair of hosts keys (which will be stored in "/etc/dropbear for re-use, default), use host keys from host system or should generate host keys at runtime on each boot. - "ip" kernel command-line parameter will now default to DHCP usage but does also support addr/CIDR notation to specify a static address. - "gk.net.iface" kernel command-line parameter was added to use a different interface than "eth0". You can either use an interface name or use a MAC address. - "gk.net.gw" kernel command-line parameter was added which will allow user to set specific gateway when DHCP isn't used. - "gk.net.routes" kernel command-line parameter was added which will allow user to set additional routes when DHCP isn't used. Please read manpage for additional parameters and more details. Signed-off-by: Thomas Deutschmann <whissi@gentoo.org>
-rw-r--r--defaults/busy-config8
-rw-r--r--defaults/initrd.defaults22
-rw-r--r--defaults/initrd.scripts302
-rw-r--r--defaults/linuxrc40
-rw-r--r--defaults/login-remote.sh152
-rw-r--r--defaults/resume-boot.sh15
-rw-r--r--defaults/software.sh14
-rw-r--r--defaults/unlock-luks.sh130
-rw-r--r--doc/genkernel.8.txt59
-rwxr-xr-xgen_cmdline.sh26
-rwxr-xr-xgen_determineargs.sh2
-rwxr-xr-xgen_funcs.sh131
-rwxr-xr-xgen_initramfs.sh313
-rwxr-xr-xgenkernel1
-rw-r--r--gkbuilds/dropbear.gkbuild68
15 files changed, 1101 insertions, 182 deletions
diff --git a/defaults/busy-config b/defaults/busy-config
index fa82f09..1184633 100644
--- a/defaults/busy-config
+++ b/defaults/busy-config
@@ -46,8 +46,8 @@ CONFIG_FEATURE_INSTALLER=y
CONFIG_LONG_OPTS=y
CONFIG_FEATURE_DEVPTS=y
# CONFIG_FEATURE_CLEAN_UP is not set
-# CONFIG_FEATURE_UTMP is not set
-# CONFIG_FEATURE_WTMP is not set
+CONFIG_FEATURE_UTMP=y
+CONFIG_FEATURE_WTMP=y
# CONFIG_FEATURE_PIDFILE is not set
CONFIG_PID_FILE_PATH=""
CONFIG_FEATURE_SUID=y
@@ -637,8 +637,8 @@ CONFIG_FEATURE_HWCLOCK_LONG_OPTIONS=y
CONFIG_IONICE=y
# CONFIG_IPCRM is not set
# CONFIG_IPCS is not set
-# CONFIG_LAST is not set
-# CONFIG_FEATURE_LAST_FANCY is not set
+CONFIG_LAST=y
+CONFIG_FEATURE_LAST_FANCY=y
CONFIG_LOSETUP=y
CONFIG_LSPCI=y
CONFIG_LSUSB=y
diff --git a/defaults/initrd.defaults b/defaults/initrd.defaults
index e1d16b8..6c6abec 100644
--- a/defaults/initrd.defaults
+++ b/defaults/initrd.defaults
@@ -70,6 +70,28 @@ CDROOT_PATH='/mnt/cdrom'
CDROOT_MARKER='/livecd'
VERIFY=0
+IP='dhcp'
+GK_NET_DHCP_PIDFILE='/var/run/udhcpc.pid'
+GK_NET_DHCP_RETRIES=3
+GK_NET_GW=
+GK_NET_IFACE='eth0'
+GK_NET_LOCKFILE='/tmp/network.started'
+GK_NET_ROUTES=
+GK_NET_TIMEOUT_DAD=10
+GK_NET_TIMEOUT_DECONFIGURATION=10
+GK_NET_TIMEOUT_DHCP=10
+GK_SHELL_LOCKFILE='/var/run/rescueshell.pid'
+GK_SSHD_LOCKFILE='/tmp/remote-rescueshell.lock'
+GK_SSHD_PIDFILE='/var/run/dropbear.pid'
+GK_SSHD_PORT=22
+GK_SSHD_WAIT=
+
+CRYPT_ENV_FILE='/etc/CRYPT_ENV.conf'
+CRYPT_KEYFILE_ROOT='/tmp/root.key'
+CRYPT_KEYFILE_SWAP='/tmp/swap.key'
+CRYPT_ROOT_OPENED_LOCKFILE='/tmp/ROOT.opened'
+CRYPT_SWAP_OPENED_LOCKFILE='/tmp/SWAP.opened'
+
# Flag for if ok when using CDROOT
got_good_root='0'
# if LOOP found on root before mount, trigger Unpacking additional packages
diff --git a/defaults/initrd.scripts b/defaults/initrd.scripts
index d56cee1..be76a4d 100644
--- a/defaults/initrd.scripts
+++ b/defaults/initrd.scripts
@@ -685,7 +685,7 @@ setup_overlayfs() {
findnfsmount() {
- if [ "${IP}" != '' ] || busybox udhcpc -n -T 15 -q
+ if start_network
then
[ -e /rootpath ] && NFSROOT=$(cat /rootpath)
@@ -1390,7 +1390,7 @@ openLUKS() {
eval local LUKS_DEVICE='"${CRYPT_'${TYPE}'}"' LUKS_NAME="$1" LUKS_KEY='"${CRYPT_'${TYPE}'_KEY}"'
eval local LUKS_KEYDEV='"${CRYPT_'${TYPE}'_KEYDEV}"' LUKS_TRIM='"${CRYPT_'${TYPE}'_TRIM}"'
- local OPENED_LOCKFILE="/${TYPE}.decrypted"
+ eval local OPENED_LOCKFILE='"${CRYPT_'${TYPE}'_OPENED_LOCKFILE}"'
local DEV_ERROR=0 KEY_ERROR=0 KEYDEV_ERROR=0
local mntkey="/mnt/key/" crypt_filter_ret= cryptsetup_options=''
@@ -1550,15 +1550,206 @@ openLUKS() {
rmdir -p "${mntkey}" >/dev/null 2>&1
}
-start_LUKS() {
- # if key is set but neither ssh enabled or key device is given, find
- # the key device
+iface_name() {
+ local ifname="${1}"
+
+ if echo "${ifname}" | grep -qE ':|-'
+ then
+ local interface=
+ local mac="$(echo "${ifname}" | sed 'y/ABCDEF-/abcdef:/')"
+
+ for interface in /sys/class/net/*
+ do
+ if [ $(cat ${interface}/address) = "${mac}" ]
+ then
+ echo ${interface##*/}
+ return
+ fi
+ done
+ else
+ echo "${ifname}"
+ fi
+}
+
+start_network() {
+ # At least gk.net.iface can only be processed after sysfs was
+ # mounted.
+ local x=
+ for x in ${CMDLINE}
+ do
+ case "${x}" in
+ ip=*)
+ IP=${x#*=}
+ ;;
+ gk.net.dhcp.retries=*)
+ local tmp_n_retries=${x#*=}
+ if is_int "${tmp_n_retries}"
+ then
+ GK_NET_DHCP_RETRIES=${tmp_n_retries}
+ else
+ warn_msg "'${x}' does not look like a valid number -- will keep using default value ${GK_NET_DHCP_RETRIES}!"
+ fi
+ unset tmp_n_retries
+ ;;
+ gk.net.gw=*)
+ GK_NET_GW=${x#*=}
+ ;;
+ gk.net.iface=*)
+ local tmp_iface=$(iface_name "${x#*=}")
+ if [ -z "${tmp_iface}" ]
+ then
+ warn_msg "Interface specified by '${x}' not found, falling back to genkernel defaults ..."
+ else
+ GK_NET_IFACE=${tmp_iface}
+ fi
+ ;;
+ gk.net.routes=*)
+ GK_NET_ROUTES=${x#*=}
+ ;;
+ gk.net.timeout.dad=*)
+ local tmp_dad_timeout=${x#*=}
+ if is_int "${tmp_dad_timeout}"
+ then
+ GK_NET_TIMEOUT_DAD=${tmp_dad_timeout}
+ else
+ warn_msg "'${x}' does not look like a valid number -- will keep using default value ${GK_NET_TIMEOUT_DAD}!"
+ fi
+ unset tmp_dad_timeout
+ ;;
+ gk.net.timeout.deconfiguration=*)
+ local tmp_deconfiguration_timeout=${x#*=}
+ if is_int "${tmp_deconfiguration_timeout}"
+ then
+ GK_NET_TIMEOUT_DECONFIGURATION=${tmp_deconfiguration_timeout}
+ else
+ warn_msg "'${x}' does not look like a valid number -- will keep using default value ${GK_NET_TIMEOUT_DECONFIGURATION}!"
+ fi
+ unset tmp_deconfiguration_timeout
+ ;;
+ gk.net.timeout.dhcp=*)
+ local tmp_dhcp_timeout=${x#*=}
+ if is_int "${tmp_dhcp_timeout}"
+ then
+ GK_NET_TIMEOUT_DHCP=${tmp_dhcp_timeout}
+ else
+ warn_msg "'${x}' does not look like a valid number -- will keep using default value ${GK_NET_TIMEOUT_DHCP}!"
+ fi
+ unset tmp_dhcp_timeout
+ ;;
+ esac
+ done
+
+ if [ -z "${IP}" -o "${IP}" = 'dhcp' ]
+ then
+ good_msg "Bringing up interface ${GK_NET_IFACE} using dhcp ..." ${QUIET}
+ busybox udhcpc -i "${GK_NET_IFACE}" -n -t ${GK_NET_DHCP_RETRIES} -T ${GK_NET_TIMEOUT_DHCP} -R -p "${GK_NET_DHCP_PIDFILE}"
+ else
+ good_msg "Bringing up interface ${GK_NET_IFACE} ..." ${QUIET}
+ ip link set "${GK_NET_IFACE}" up
+
+ good_msg "Setting address '${IP}' on ${GK_NET_IFACE} ..." ${QUIET}
+ ip addr add "${IP}" dev "${GK_NET_IFACE}"
+
+ if [ -n "${GK_NET_ROUTES}" ]
+ then
+ local route=
+ for route in ${GK_NET_ROUTES}
+ do
+ good_msg "Adding additional route '${route}' on ${GK_NET_IFACE} ..." ${QUIET}
+ ip route add "${route}" dev "${GK_NET_IFACE}"
+ done
+ fi
+
+ if [ -n "${GK_NET_GW}" ]
+ then
+ good_msg "Adding default route via '${GK_NET_GW}' on ${GK_NET_IFACE} ..." ${QUIET}
+ ip route add default via "${GK_NET_GW}" dev "${GK_NET_IFACE}"
+ fi
+ fi
+
+ touch "${GK_NET_LOCKFILE}"
+}
- if [ -e "/usr/sbin/dropbear" ]
+kill_network() {
+ if [ -s "${GK_NET_DHCP_PIDFILE}" ]
then
- startdropbear
+ good_msg "Stopping udhcpc ..."
+ kill $(cat "${GK_NET_DHCP_PIDFILE}")
+ fi
+
+ # If we are too quick and interface is still configuring IPv6
+ # waiting for DAD to complete due to received IPv6 RA, we have to
+ # wait.
+ # If we don't wait, ip command will bring down interface for a
+ # moment but it will return to up state once DAD is completed which
+ # will cause trouble with real system which is expecting an unused
+ # interface.
+ if ipv6_tentative
+ then
+ [ -z "${QUIET}" ] && \
+ printf "%b" "${WARN}**${NORMAL}${BOLD} Waiting for tentative IPv6 addresses to complete DAD ${NORMAL}..."
+
+ local dad_timeout=10
+ while [ ${dad_timeout} -gt 0 ]
+ do
+ ipv6_tentative || break
+ sleep 1
+ : $(( dad_timeout -= 1 ))
+ [ -z "${QUIET}" ] && \
+ printf "."
+ done
+
+ echo ""
+
+ if [ ${dad_timeout} -le 0 ]
+ then
+ bad_msg "DAD still not completed after ${GK_NET_TIMEOUT_DAD} seconds!"
+ fi
fi
+ [ -z "${QUIET}" ] && \
+ printf "%b" "${GOOD}>>${NORMAL}${BOLD} Bringing down interface ${GK_NET_IFACE} ${NORMAL}..."
+
+ local deconfiguration_timeout=${GK_NET_TIMEOUT_DECONFIGURATION}
+ while [ ${deconfiguration_timeout} -gt 0 ]
+ do
+ ip addr flush dev "${GK_NET_IFACE}"
+ ip route flush dev "${GK_NET_IFACE}"
+ ip link set "${GK_NET_IFACE}" down
+ if grep -q "down" "/sys/class/net/${GK_NET_IFACE}/operstate"
+ then
+ break
+ fi
+ sleep 1
+ : $(( deconfiguration_timeout -= 1 ))
+ [ -z "${QUIET}" ] && \
+ printf "."
+ done
+
+ echo ""
+
+ if [ ${deconfiguration_timeout} -le 0 ]
+ then
+ bad_msg "Failed to bring down interface ${GK_NET_IFACE} within ${GK_NET_TIMEOUT_DECONFIGURATION} seconds!"
+ return
+ fi
+
+ rm "${GK_NET_LOCKFILE}"
+}
+
+ipv6_tentative() {
+ if ip -family inet6 addr show dev "${GK_NET_IFACE}" | grep -q " tentative "
+ then
+ return 0
+ else
+ return 1
+ fi
+}
+
+start_LUKS() {
+ # if key is set but neither ssh enabled or key device is given, find
+ # the key device
+
[ -n "${CRYPT_ROOT_KEY}" ] && [ -z "${CRYPT_ROOT_KEYDEV}" ] \
&& sleep 6 && bootstrapKey "ROOT"
@@ -1589,6 +1780,103 @@ start_LUKS() {
fi
}
+start_sshd() {
+ if [ -s "${GK_SSHD_PIDFILE}" ]
+ then
+ # Already running
+ return
+ fi
+
+ if [ ! -x "/usr/sbin/dropbear" ]
+ then
+ bad_msg "/usr/sbin/dropbear not found! Did you call genkernel with --ssh parameter?"
+ return
+ fi
+
+ # setup environment variables for the ssh login shell
+ local varname= varvalue=
+ touch "${CRYPT_ENV_FILE}"
+ for varname in CRYPT_ROOT CRYPT_ROOT_TRIM CRYPT_SILENT CRYPT_SWAP DEBUG
+ do
+ eval varvalue=\$${varname}
+ echo "${varname}=${varvalue}" >> "${CRYPT_ENV_FILE}"
+ done
+
+ touch /var/log/lastlog
+
+ good_msg "Starting dropbear sshd ..." ${QUIET}
+ /usr/sbin/dropbear -p ${GK_SSHD_PORT} -R -P "${GK_SSHD_PIDFILE}" 2>/var/log/dropbear.log
+ test_success "Failed to start dropbear"
+}
+
+wait_sshd() {
+ if [ -z "${GK_SSHD_WAIT}" -o "${GK_SSHD_WAIT}" = '0' ]
+ then
+ return
+ fi
+
+ if [ -f "${GK_SSHD_LOCKFILE}" -o ! -s "${GK_SSHD_PIDFILE}" ]
+ then
+ return
+ fi
+
+ printf "%b" "${GOOD}>>${NORMAL}${BOLD} gk.sshd.wait set; Waiting ${GK_SSHD_WAIT} seconds for SSH connection ${NORMAL}..."
+
+ local ssh_timeout=${GK_SSHD_WAIT}
+ while [ ${ssh_timeout} -gt 0 ]
+ do
+ if [ -f "${GK_SSHD_LOCKFILE}" ]
+ then
+ echo ""
+ last -W | head -n 3 2>/dev/null
+ break
+ fi
+ sleep 1
+ : $(( ssh_timeout -= 1 ))
+ printf "."
+ done
+
+ echo ""
+}
+
+kill_sshd() {
+ if [ -s "${GK_SSHD_PIDFILE}" ]
+ then
+ good_msg "Stopping dropbear sshd ..." ${QUIET}
+ kill $(cat "${GK_SSHD_PIDFILE}")
+ fi
+}
+
+cleanup() {
+ if [ -f "${GK_NET_LOCKFILE}" ]
+ then
+ if [ -f "${GK_SSHD_LOCKFILE}" ]
+ then
+ warn_msg "The lockfile at '${GK_SSHD_LOCKFILE}' exists."
+ warn_msg "The boot process will be paused until the lock is removed."
+ while true
+ do
+ if [ -f "${GK_SSHD_LOCKFILE}" ]
+ then
+ sleep 1
+ else
+ break
+ fi
+ done
+ fi
+ fi
+
+ kill_sshd
+
+ # Ensure that we terminated any existing connection
+ pkill -9 dropbear >/dev/null 2>&1
+
+ if [ -f "${GK_NET_LOCKFILE}" ]
+ then
+ kill_network
+ fi
+}
+
sdelay() {
# Sleep a specific number of seconds if SDELAY is set
if [ -n "${SDELAY}" ]
diff --git a/defaults/linuxrc b/defaults/linuxrc
index 999f05c..e0a4115 100644
--- a/defaults/linuxrc
+++ b/defaults/linuxrc
@@ -191,10 +191,8 @@ do
part|partitionable)
MDPART=1
;;
+ # For network options see start_network() in initrd.scripts
# NFS
- ip=*)
- IP=${x#*=}
- ;;
nfsroot=*)
NFSROOT=${x#*=}
;;
@@ -263,6 +261,29 @@ do
crypt_silent)
CRYPT_SILENT=1
;;
+ dosshd)
+ USE_SSH=1
+ ;;
+ gk.sshd.port=*)
+ tmp_port=${x#*=}
+ if is_int "${tmp_port}"
+ then
+ GK_SSHD_PORT=${tmp_port}
+ else
+ warn_msg "'${x}' does not look like a valid port -- ignored!"
+ fi
+ unset tmp_port
+ ;;
+ gk.sshd.wait=*)
+ tmp_wait=${x#*=}
+ if is_int "${tmp_wait}"
+ then
+ GK_SSHD_WAIT=${tmp_wait}
+ else
+ warn_msg "'${x}' does not look like a valid time (second) value -- ignored!"
+ fi
+ unset tmp_wait
+ ;;
real_rootflags=*)
REAL_ROOTFLAGS=${x#*=}
;;
@@ -467,6 +488,12 @@ start_volumes
setup_keymap
+if [ "${USE_SSH}" = '1' ]
+then
+ start_network
+ start_sshd
+fi
+
# Initialize LUKS root device except for livecd's
if [ "${CDROOT}" != '1' ]
then
@@ -1113,6 +1140,13 @@ copyKeymap
# Setup any user defined environment locales for desktop usage
setup_locale
+if [ "${USE_SSH}" = '1' ]
+then
+ wait_sshd
+fi
+
+cleanup
+
good_msg "Booting (initramfs)"
cd "${CHROOT}"
diff --git a/defaults/login-remote.sh b/defaults/login-remote.sh
index c667b5e..7f711da 100644
--- a/defaults/login-remote.sh
+++ b/defaults/login-remote.sh
@@ -1,11 +1,9 @@
#!/bin/sh
# vim: set noexpandtab:
-. /etc/login-remote.conf
. /etc/initrd.defaults
. /etc/initrd.scripts
-KEYFILE_ROOT="/tmp/root.key"
-KEYFILE_SWAP="/tmp/swap.key"
+. "${CRYPT_ENV_FILE}"
splash() {
return 0
@@ -16,109 +14,23 @@ splash() {
receivefile() {
case ${1} in
root)
- file=${KEYFILE_ROOT}
+ file=${CRYPT_KEYFILE_ROOT}
;;
swap)
- file=${KEYFILE_SWAP}
+ file=${CRYPT_KEYFILE_SWAP}
+ ;;
+ *)
+ bad_msg "Unknown '${1}' keyfile received." ${CRYPT_SILENT}
+ exit 1
;;
esac
+
# limit maximum stored bytes to 1M to avoid killing the server
dd of=${file} count=1k bs=1k 2>/dev/null
- exit $?
+ return $?
}
-openLUKSremote() {
- case $1 in
- root)
- local TYPE=ROOT
- ;;
- swap)
- local TYPE=SWAP
- ;;
- esac
-
- [ ! -d /tmp/key ] && mkdir -p /tmp/key
-
- eval local LUKS_DEVICE='"${CRYPT_'${TYPE}'}"' LUKS_NAME="$1" LUKS_KEY='"${KEYFILE_'${TYPE}'}"'
- local DEV_ERROR=0 KEY_ERROR=0
- local input="" cryptsetup_options="" flag_opened="/${TYPE}.decrypted"
- while [ 1 ]
- do
- local gpg_cmd="" crypt_filter_ret=42
-
- if [ -e ${flag_opened} ]
- then
- good_msg "The LUKS device ${LUKS_DEVICE} meanwhile was opened by someone else."
- break
- elif [ ${DEV_ERROR} -eq 1 ]
- then
- prompt_user "LUKS_DEVICE" "${LUKS_NAME}"
- DEV_ERROR=0
- else
- LUKS_DEVICE=$(find_real_device "${LUKS_DEVICE}")
-
- setup_md_device ${LUKS_DEVICE}
- cryptsetup isLuks ${LUKS_DEVICE}
- if [ $? -ne 0 ]
- then
- bad_msg "The LUKS device ${LUKS_DEVICE} does not contain a LUKS header" ${CRYPT_SILENT}
- DEV_ERROR=1
- continue
- else
- # Handle keys
- if [ "x${LUKS_TRIM}" = "xyes" ]
- then
- good_msg "Enabling TRIM support for ${LUKS_NAME}." ${CRYPT_SILENT}
- cryptsetup_options="${cryptsetup_options} --allow-discards"
- fi
-
- if [ ${crypt_filter_ret} -ne 0 ]
- then
- # 1st try: unencrypted keyfile
- crypt_filter "cryptsetup ${cryptsetup_options} --key-file ${LUKS_KEY} luksOpen ${LUKS_DEVICE} ${LUKS_NAME}"
- crypt_filter_ret=$?
- fi
-
- if [ -f /sbin/gpg ] && [ ${crypt_filter_ret} -ne 0 ]
- then
- # 2nd try: gpg-encrypted keyfile
- [ -e /dev/tty ] && mv /dev/tty /dev/tty.org
- mknod /dev/tty c 5 1
- gpg_cmd="/sbin/gpg --logger-file /dev/null --quiet --decrypt ${LUKS_KEY} |"
- crypt_filter "${gpg_cmd}cryptsetup ${cryptsetup_options} --key-file ${LUKS_KEY} luksOpen ${LUKS_DEVICE} ${LUKS_NAME}"
- crypt_filter_ret=$?
- [ -e /dev/tty.org ] \
- && rm -f /dev/tty \
- && mv /dev/tty.org /dev/tty
- fi
-
- if [ ${crypt_filter_ret} -ne 0 ]
- then
- # 3rd try: user-submitted passphrase
- crypt_filter "cryptsetup ${cryptsetup_options} luksOpen ${LUKS_DEVICE} ${LUKS_NAME}"
- crypt_filter_ret=$?
- fi
-
- if [ ${crypt_filter_ret} -eq 0 ]
- then
- touch ${flag_opened}
- good_msg "LUKS device ${LUKS_DEVICE} opened" ${CRYPT_SILENT}
- # Kill the cryptsetup process started by init
- # so that the boot process can continue
- killall cryptsetup
- break
- else
- bad_msg "Failed to open LUKS device ${LUKS_DEVICE}" ${CRYPT_SILENT}
- DEV_ERROR=1
- fi
- fi
- fi
- done
- rm -f ${LUKS_KEY}
- cd /
- rmdir -p tmp/key
-}
if [ "x${1}" = "x-c" ]
then
@@ -128,9 +40,51 @@ then
case ${command} in
post)
receivefile ${type}
+ if [ $? -eq 0 ]
+ then
+ unlock-luks ${type}
+ if [ $? -eq 0 ]
+ then
+ if [ "${type}" = 'root' ]
+ then
+ # this is required to keep scripted unlock working
+ # without requring an additional command.
+ resume-boot
+ fi
+
+ exit 0
+ else
+ exit 1
+ fi
+ else
+ bad_msg "Keyfile was not properly received!" ${CRYPT_SILENT}
+ exit 1
+ fi
;;
+ *)
+ bad_msg "Command '${command}' is not supported!" ${CRYPT_SILENT}
+ exit 1
esac
else
- [ -n "${CRYPT_ROOT}" ] && openLUKSremote root
- [ -n "${CRYPT_SWAP}" ] && openLUKSremote swap
+ export PS1='remote rescueshell \w \# '
+ touch "${GK_SSHD_LOCKFILE}"
+ good_msg "The lockfile '${GK_SSHD_LOCKFILE}' was created."
+ good_msg "In order to resume boot process, run 'resume-boot'."
+ good_msg "Be aware that it will kill your connection which means"
+ good_msg "you will no longer be able work in this shell."
+
+ if [ -n "${CRYPT_ROOT}" -a ! -f "${CRYPT_ROOT_OPENED_LOCKFILE}" ]
+ then
+ good_msg "To remote unlock LUKS-encrypted root device, run 'unlock-luks root'."
+ fi
+
+ if [ -n "${CRYPT_SWAP}" -a ! -f "${CRYPT_ROOT_OPENED_LOCKFILE}" ]
+ then
+ good_msg "To remote unlock LUKS-encrypted swap device, run 'unlock-luks swap'."
+ fi
+
+ [ -x /bin/sh ] && SH=/bin/sh || SH=/bin/ash
+ exec ${SH} --login
fi
+
+exit 0
diff --git a/defaults/resume-boot.sh b/defaults/resume-boot.sh
new file mode 100644
index 0000000..cb29831
--- /dev/null
+++ b/defaults/resume-boot.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+. /etc/initrd.defaults
+
+if [ -s "${GK_SHELL_LOCKFILE}" ]
+then
+ kill -9 "$(cat "${GK_SHELL_LOCKFILE}")"
+fi
+
+if [ -f "${GK_SSHD_LOCKFILE}" ]
+then
+ rm "${GK_SSHD_LOCKFILE}"
+fi
+
+exit 0
diff --git a/defaults/software.sh b/defaults/software.sh
index 5a0d773..420eb62 100644
--- a/defaults/software.sh
+++ b/defaults/software.sh
@@ -36,6 +36,13 @@ DMRAID_DIR="${DMRAID_DIR:-dmraid/${DMRAID_VER}/dmraid}"
DMRAID_SRCTAR="${DMRAID_SRCTAR:-${DISTDIR}/dmraid-${DMRAID_VER}.tar.bz2}"
DMRAID_BINCACHE="${DMRAID_BINCACHE:-%%CACHE%%/dmraid-${DMRAID_VER}-%%ARCH%%.tar.bz2}"
+GKPKG_DROPBEAR_PN="dropbear"
+GKPKG_DROPBEAR_PV="${GKPKG_DROPBEAR_PV:-VERSION_DROPBEAR}"
+GKPKG_DROPBEAR_DEPS="zlib"
+GKPKG_DROPBEAR_SRCTAR="${GKPKG_DROPBEAR_SRCTAR:-${DISTDIR}/dropbear-${GKPKG_DROPBEAR_PV}.tar.bz2}"
+GKPKG_DROPBEAR_SRCDIR="${GKPKG_DROPBEAR_SRCDIR:-dropbear-${GKPKG_DROPBEAR_PV}}"
+GKPKG_DROPBEAR_BINPKG="${GKPKG_DROPBEAR_BINPKG:-%%CACHE%%/dropbear-${GKPKG_DROPBEAR_PV}-%%ARCH%%.tar.xz}"
+
GKPKG_E2FSPROGS_PN="e2fsprogs"
GKPKG_E2FSPROGS_PV="${GKPKG_E2FSPROGS_PV:-VERSION_E2FSPROGS}"
GKPKG_E2FSPROGS_DEPS="util-linux"
@@ -77,3 +84,10 @@ GKPKG_UTIL_LINUX_DEPS=""
GKPKG_UTIL_LINUX_SRCDIR="${GKPKG_UTIL_LINUX_SRCDIR:-util-linux-${GKPKG_UTIL_LINUX_PV}}"
GKPKG_UTIL_LINUX_SRCTAR="${GKPKG_UTIL_LINUX_SRCTAR:-${DISTDIR}/util-linux-${GKPKG_UTIL_LINUX_PV}.tar.xz}"
GKPKG_UTIL_LINUX_BINPKG="${GKPKG_UTIL_LINUX_BINPKG:-%%CACHE%%/util-linux-${GKPKG_UTIL_LINUX_PV}-%%ARCH%%.tar.xz}"
+
+GKPKG_ZLIB_PN="zlib"
+GKPKG_ZLIB_PV="${GKPKG_ZLIB_PV:-VERSION_ZLIB}"
+GKPKG_ZLIB_DEPS=""
+GKPKG_ZLIB_SRCDIR="${GKPKG_ZLIB_SRCDIR:-zlib-${GKPKG_ZLIB_PV}}"
+GKPKG_ZLIB_SRCTAR="${GKPKG_ZLIB_SRCTAR:-${DISTDIR}/zlib-${GKPKG_ZLIB_PV}.tar.gz}"
+GKPKG_ZLIB_BINPKG="${GKPKG_ZLIB_BINPKG:-%%CACHE%%/zlib-${GKPKG_ZLIB_PV}-%%ARCH%%.tar.xz}"
diff --git a/defaults/unlock-luks.sh b/defaults/unlock-luks.sh
new file mode 100644
index 0000000..ef6b816
--- /dev/null
+++ b/defaults/unlock-luks.sh
@@ -0,0 +1,130 @@
+#!/bin/sh
+
+print_usage() {
+ echo "Usage: $0 root|swap" >&2
+}
+
+splash() {
+ return 0
+}
+
+if [ -z "${1}" ]
+then
+ print_usage
+ exit 1
+fi
+
+case "${1}" in
+ root)
+ NAME="${1}"
+ TYPE=ROOT
+ ;;
+ swap)
+ NAME="${1}"
+ TYPE=SWAP
+ ;;
+ *)
+ echo "ERROR: Unknown type '${1}' specified!"
+ print_usage
+ exit 1
+ ;;
+esac
+
+. /etc/initrd.defaults
+. /etc/initrd.scripts
+. "${CRYPT_ENV_FILE}"
+
+main() {
+ if [ ! -x /sbin/cryptsetup ]
+ then
+ bad_msg "cryptsetup program is missing. Was initramfs built without --luks parameter?"
+ exit 1
+ fi
+
+ eval local LUKS_DEVICE='"${CRYPT_'${TYPE}'}"' LUKS_NAME="${NAME}" LUKS_KEY='"${CRYPT_KEYFILE_'${TYPE}'}"'
+ eval local LUKS_TRIM='"${CRYPT_'${TYPE}'_TRIM}"' OPENED_LOCKFILE='"${CRYPT_'${TYPE}'_OPENED_LOCKFILE}"'
+ local cryptsetup_options=
+
+ while true
+ do
+ local gpg_cmd= crypt_filter_ret=
+
+ if [ -e "${OPENED_LOCKFILE}" ]
+ then
+ good_msg "The LUKS device ${LUKS_DEVICE} was opened by someone else in the meanwhile."
+ break
+ else
+ LUKS_DEVICE=$(find_real_device "${LUKS_DEVICE}")
+ if [ -z "${LUKS_DEVICE}" ]
+ then
+ bad_msg "Looks like CRYPT_${TYPE} kernel cmdline argument is not set." ${CRYPT_SILENT}
+ exit 1
+ fi
+
+ setup_md_device ${LUKS_DEVICE}
+ cryptsetup isLuks ${LUKS_DEVICE}
+ if [ $? -ne 0 ]
+ then
+ bad_msg "The LUKS device ${LUKS_DEVICE} does not contain a LUKS header" ${CRYPT_SILENT}
+
+ # User has SSH access and is able to call script again or
+ # able to investigate the problem on its own.
+ exit 1
+ else
+ if [ "x${LUKS_TRIM}" = "xyes" ]
+ then
+ good_msg "Enabling TRIM support for ${LUKS_NAME} ..." ${CRYPT_SILENT}
+ cryptsetup_options="${cryptsetup_options} --allow-discards"
+ fi
+
+ # Handle keys
+ if [ -s "${LUKS_KEY}" ]
+ then
+ # we received raw, unencrypted key through SSH -- no GPG possible
+ cryptsetup_options="${cryptsetup_options} -d ${LUKS_KEY}"
+ fi
+
+ # At this point, keyfile or not, we're ready!
+ crypt_filter "${gpg_cmd}cryptsetup ${cryptsetup_options} luksOpen ${LUKS_DEVICE} ${LUKS_NAME}"
+ crypt_filter_ret=$?
+
+ [ -e /dev/tty.org ] \
+ && rm -f /dev/tty \
+ && mv /dev/tty.org /dev/tty
+
+ if [ ${crypt_filter_ret} -eq 0 ]
+ then
+ touch "${OPENED_LOCKFILE}"
+ good_msg "LUKS device ${LUKS_DEVICE} opened" ${CRYPT_SILENT}
+ break
+ else
+ bad_msg "Failed to open LUKS device ${LUKS_DEVICE}" ${CRYPT_SILENT}
+
+ # We need to stop here with a non-zero exit code to prevent
+ # a loop when invalid keyfile was sent.
+ exit 1
+ fi
+ fi
+ fi
+ done
+
+ if [ -s "${LUKS_KEY}" ]
+ then
+ if [ "${DEBUG}" != 'yes' ]
+ then
+ rm -f "${LUKS_KEY}"
+ else
+ warn_msg "LUKS key file '${LUKS_KEY}' not deleted because DEBUG mode is enabled!"
+ fi
+ fi
+
+ if [ "${crypt_filter_ret}" = '0' ]
+ then
+ # Kill any running cryptsetup prompt for this device
+ pkill -9 -f "luksOpen.*${LUKS_NAME}\$" >/dev/null 2>&1
+ fi
+}
+
+main
+
+exit 0
diff --git a/doc/genkernel.8.txt b/doc/genkernel.8.txt
index 2832277..055610b 100644
--- a/doc/genkernel.8.txt
+++ b/doc/genkernel.8.txt
@@ -317,6 +317,19 @@ INITIALIZATION
*--*[*no-*]*ssh*::
Includes or excludes SSH (dropbear) support for remote LUKS keys.
+*--ssh-authorized-keys-file*=<file>::
+ Specifies a user created authorized_keys file. By default genkernel
+ will use "/etc/dropbear/authorized_keys".
+
+*--ssh-host-keys*=<create|create-from-host|runtime>::
+ When set to *create*, which is the default value, genkernel will embed
+ SSH host keys from "/etc/dropbear" and will create those keys when missing.
+ When set to *create-from-host*, genkernel will embed SSH host keys from
+ "/etc/dropbear" but will create those keys from "/etc/ssh" when missing
+ (not recommended for security reasons).
+ When set to *runtime*, genkernel will not embed any SSH host key in
+ initramfs and dropbear will generate needed host key at runtime (`dropbear -R`).
+
*--bootloader*=<grub|grub2>::
Add new kernel to GRUB or GRUB2 configuration.
@@ -512,10 +525,50 @@ recognized by the kernel itself.
Pauses for up to 3 seconds (or specified number of seconds) while
waiting for root device to appear during initramfs root scanning.
-*ip*=<...>::
+*ip*=<dhcp,addr/cidr>::
Normally used to tell the kernel that it should start a network
- interface. If present, the initrd will try to mount a livecd
- over NFS.
+ interface which can be specified using *gk.net.iface* kernel parameter.
+ By default, dhcp will be used. You can set a specific IP address using
+ addr/CIDR notation, i.e. '1.2.3.4/24'.
+
+*gk.net.iface*=<interface,macaddr>::
+ By default we will use the interface named eth0. Use this kernel
+ parameter to specify another interface. You can also specify a MAC
+ address (00:00:00:00:00:00 format) instead of an interface name.
+
+*gk.net.timeout.dhcp*=<...>::
+ By default we will send up to 3 DHCP discovery requests.
+
+*gk.net.gw*=<...>::
+ Optional gateway. If *ip* is set to dhcp, this kernel parameter will
+ be ignored.
+
+*gk.net.routes*=<...>::
+ Optional additional routes. If *ip* is set to dhcp, this kernel
+ parameter will be ignored.
+
+*gk.net.timeout.dad*=<...>::
+ By default we will wait up to 10 seconds for IPv6's DAD to complete.
+ At the moment, we only wait for DAD while bringing down an interface
+ to prevent a race condition.
+
+*gk.net.timeout.deconfiguration*=<...>::
+ By default we will wait up to 10 seconds while bringing down an
+ interface to prevent a race condition.
+
+*gk.net.timeout.dhcp*=<...>::
+ By default we will wait up to 10 seconds for a DHCP server reply.
+
+*dosshd*::
+ Will start an SSH daemon within initramfs allowing to remotely unlock
+ encrypted devices or just for debugging purpose.
+
+*gk.sshd.port*=<...>::
+ By default, sshd will listen on port 22.
+
+*gk.sshd.wait*=<...>::
+ Wait X seconds after setting up sshd, useful when you want to login
+ (and thus pause boot process) before booting real system.
*nfsroot*=<...>::
If present, the initrd will try to mount a livecd from that
diff --git a/gen_cmdline.sh b/gen_cmdline.sh
index a22b607..0a1b1c8 100755
--- a/gen_cmdline.sh
+++ b/gen_cmdline.sh
@@ -128,6 +128,13 @@ longusage() {
echo " --no-iscsi Exclude iSCSI support"
echo " --ssh Include SSH (dropbear) support"
echo " --no-ssh Exclude SSH (dropbear) support"
+ echo " --ssh-authorized-keys-file=<file>"
+ echo " Specifies a user created authorized_keys file"
+ echo " --ssh-host-keys=(create|create-from-host|runtime)"
+ echo " Use host keys from /etc/dropbear, but CREATE (default) new host key(s)"
+ echo " if missing, CREATE host key(s) FROM current HOST running genkernel"
+ echo " (not recommended) or don't embed any host key in initramfs and"
+ echo " generate at RUNTIME (dropbear -R)"
echo " --bootloader=(grub|grub2)"
echo " Add new kernel to GRUB (grub) or GRUB2 (grub2) bootloader"
echo " --no-bootloader Skip bootloader update"
@@ -445,18 +452,19 @@ parse_cmdline() {
--ssh|--no-ssh)
CMD_SSH=$(parse_optbool "$*")
print_info 2 "CMD_SSH: ${CMD_SSH}"
- if isTrue "${CMD_SSH}" && [ ! -e /usr/sbin/dropbear ]
- then
- echo 'Error: --ssh requires net-misc/dropbear' \
- 'to be installed on the host system.'
- exit 1
- fi
- if isTrue "${CMD_SSH}" && [ ! -e /etc/dropbear/authorized_keys ]
+ ;;
+ --ssh-authorized-keys-file=*)
+ CMD_SSH_AUTHORIZED_KEYS_FILE="${*#*=}"
+ print_info 2 "CMD_SSH_AUTHORIZED_KEYS_FILE: ${CMD_SSH_AUTHORIZED_KEYS_FILE}"
+ ;;
+ --ssh-host-keys=*)
+ CMD_SSH_HOST_KEYS="${*#*=}"
+ if ! isTrue "$(is_valid_ssh_host_keys_parameter_value "${CMD_SSH_HOST_KEYS}")"
then
- echo 'Error: --ssh requires that dropbear is configured' \
- 'but /etc/dropbear/authorized_keys does not exist!'
+ echo "Error: --ssh-host-keys value '${CMD_SSH_HOST_KEYS}' is unsupported."
exit 1
fi
+ print_info 2 "CMD_SSH_HOST_KEYS: ${CMD_SSH_HOST_KEYS}"
;;
--loglevel=*)
CMD_LOGLEVEL="${*#*=}"
diff --git a/gen_determineargs.sh b/gen_determineargs.sh
index 1e73bc1..a698f77 100755
--- a/gen_determineargs.sh
+++ b/gen_determineargs.sh
@@ -144,6 +144,8 @@ determine_real_args() {
set_config_with_override STRING INSTALL_MOD_PATH CMD_INSTALL_MOD_PATH
set_config_with_override BOOL OLDCONFIG CMD_OLDCONFIG "yes"
set_config_with_override BOOL SSH CMD_SSH "no"
+ set_config_with_override STRING SSH_AUTHORIZED_KEYS_FILE CMD_SSH_AUTHORIZED_KEYS_FILE "/etc/dropbear/authorized_keys"
+ set_config_with_override STRING SSH_HOST_KEYS CMD_SSH_HOST_KEYS "create"
set_config_with_override BOOL LVM CMD_LVM "no"
set_config_with_override BOOL DMRAID CMD_DMRAID "no"
set_config_with_override BOOL ISCSI CMD_ISCSI "no"
diff --git a/gen_funcs.sh b/gen_funcs.sh
index 79daedf..4136122 100755
--- a/gen_funcs.sh
+++ b/gen_funcs.sh
@@ -201,6 +201,19 @@ can_run_programs_compiled_by_genkernel() {
echo "${can_run_programs}"
}
+is_valid_ssh_host_keys_parameter_value() {
+ local parameter_value=${1}
+
+ local is_valid=no
+ case "${parameter_value}" in
+ create|create-from-host|runtime)
+ is_valid=yes
+ ;;
+ esac
+
+ echo "${is_valid}"
+}
+
is_valid_triplet() {
[[ ${#} -ne 1 ]] \
&& gen_die "$(get_useful_function_stack "${FUNCNAME}")Invalid usage of ${FUNCNAME}(): Function takes exactly one argument (${#} given)!"
@@ -526,6 +539,124 @@ copy_image_with_preserve() {
fi
}
+dropbear_create_key() {
+ [[ ${#} -ne 2 ]] \
+ && gen_die "$(get_useful_function_stack "${FUNCNAME}")Invalid usage of ${FUNCNAME}(): Function takes exactly two arguments (${#} given)!"
+
+ if ! hash sandbox &>/dev/null
+ then
+ gen_die "Sandbox not found. Please install sys-apps/sandbox!"
+ fi
+
+ local key_file=${1}
+ local command=${2}
+ local key_type=$(dropbear_get_key_type_from_filename "${key_file}")
+
+ local -a envvars=(
+ GK_SHARE="${GK_SHARE}"
+ LOGLEVEL="${LOGLEVEL}"
+ LOGFILE="${LOGFILE}"
+ NOCOLOR="${NOCOLOR}"
+ TEMP="${TEMP}"
+ SANDBOX_WRITE="${LOGFILE}:${TEMP}"
+ )
+
+ envvars+=(
+ DROPBEAR_COMMAND="${command}"
+ DROPBEAR_KEY_FILE="${key_file}"
+ DROPBEAR_KEY_TYPE="${key_type}"
+ )
+
+ # set up worker signal handler
+ local error_msg_detail="Failed to create dropbear key '${key_file}'!"
+ local error_msg="gen_worker.sh aborted: ${error_msg_detail}"
+ trap "gen_die \"${error_msg}\"" SIGABRT SIGHUP SIGQUIT SIGINT SIGTERM
+
+ env -i \
+ "${envvars[@]}" \
+ sandbox "${GK_SHARE}"/gen_worker.sh dropbear 2>&1
+
+ local RET=$?
+
+ # restore default trap
+ set_default_gk_trap
+
+ [ ${RET} -ne 0 ] && gen_die "$(get_useful_function_stack)${error_msg_detail}"
+}
+
+dropbear_get_key_type_from_filename() {
+ [[ ${#} -ne 1 ]] \
+ && gen_die "$(get_useful_function_stack "${FUNCNAME}")Invalid usage of ${FUNCNAME}(): Function takes exactly one argument (${#} given)!"
+
+ local key=${1}
+ local type=
+
+ case "${key}" in
+ *_dss_*)
+ type=dss
+ ;;
+ *_ecdsa_*)
+ type=ecdsa
+ ;;
+ *_rsa_*)
+ type=rsa
+ ;;
+ *)
+ gen_die "Failed to determine key type from '${key}'!"
+ ;;
+ esac
+
+ echo "${type}"
+}
+
+dropbear_generate_key_info_file() {
+ [[ ${#} -ne 3 ]] \
+ && gen_die "$(get_useful_function_stack "${FUNCNAME}")Invalid usage of ${FUNCNAME}(): Function takes exactly three arguments (${#} given)!"
+
+ if ! hash sandbox &>/dev/null
+ then
+ gen_die "Sandbox not found. Please install sys-apps/sandbox!"
+ fi
+
+ local command=${1}
+ local key_info_file=${2}
+ local initramfs_dropbear_dir=${3}
+ local key_file="${initramfs_dropbear_dir}/$(basename "${key_info_file/%_key.*/_key}")"
+ local key_type=$(dropbear_get_key_type_from_filename "${key_file}")
+
+ local -a envvars=(
+ GK_SHARE="${GK_SHARE}"
+ LOGLEVEL="${LOGLEVEL}"
+ LOGFILE="${LOGFILE}"
+ NOCOLOR="${NOCOLOR}"
+ TEMP="${TEMP}"
+ SANDBOX_WRITE="${LOGFILE}:${TEMP}"
+ )
+
+ envvars+=(
+ DROPBEAR_COMMAND="${command}"
+ DROPBEAR_KEY_FILE="${key_file}"
+ DROPBEAR_KEY_TYPE="${key_type}"
+ DROPBEAR_KEY_INFO_FILE="${key_info_file}"
+ )
+
+ # set up worker signal handler
+ local error_msg_detail="Failed to extract dropbear key information from '${key_file}'!"
+ local error_msg="gen_worker.sh aborted: ${error_msg_detail}"
+ trap "gen_die \"${error_msg}\"" SIGABRT SIGHUP SIGQUIT SIGINT SIGTERM
+
+ env -i \
+ "${envvars[@]}" \
+ sandbox "${GK_SHARE}"/gen_worker.sh dropbear 2>&1
+
+ local RET=$?
+
+ # restore default trap
+ set_default_gk_trap
+
+ [ ${RET} -ne 0 ] && gen_die "$(get_useful_function_stack)${error_msg_detail}"
+}
+
# @FUNCTION: debug_breakpoint
# @USAGE: [<NAME>]
# @DESCRIPTION:
diff --git a/gen_initramfs.sh b/gen_initramfs.sh
index 35ec279..0b660da 100755
--- a/gen_initramfs.sh
+++ b/gen_initramfs.sh
@@ -754,90 +754,289 @@ append_luks() {
rm -r "${TEMP}/initramfs-luks-temp/"
}
-append_dropbear(){
- if [ -d "${TEMP}"/initramfs-dropbear-temp ]
+append_dropbear() {
+ local PN=dropbear
+ local TDIR="${TEMP}/initramfs-${PN}-temp"
+ if [ -d "${TDIR}" ]
then
- rm -r "${TEMP}"/initramfs-dropbear-temp
+ rm -r "${TDIR}" || gen_die "Failed to clean out existing '${TDIR}'!"
fi
- if [ ! -d /etc/dropbear ]
+ local dropbear_command=
+ if ! isTrue "$(is_valid_ssh_host_keys_parameter_value "${SSH_HOST_KEYS}")"
then
- mkdir /etc/dropbear
+ gen_die "--ssh-host-keys value '${SSH_HOST_KEYS}' is unsupported!"
+ elif [[ "${SSH_HOST_KEYS}" == 'create' ]]
+ then
+ dropbear_command=dropbearkey
+ else
+ dropbear_command=dropbearconvert
fi
- if [ ! -e /etc/dropbear/dropbear_rsa_host_key ]
+
+ local ssh_authorized_keys_file=$(expand_file "${SSH_AUTHORIZED_KEYS_FILE}")
+ if [ -z "${ssh_authorized_keys_file}" ]
then
- if [ -e /usr/bin/dropbearconvert -a /etc/ssh/ssh_host_rsa_key ]
+ gen_die "--ssh-authorized-keys value '${SSH_AUTHORIZED_KEYS_FILE}' is invalid!"
+ elif [ ! -f "${ssh_authorized_keys_file}" ]
+ then
+ gen_die "authorized_keys file '${ssh_authorized_keys_file}' does NOT exist!"
+ elif [ ! -s "${ssh_authorized_keys_file}" ]
+ then
+ gen_die "authorized_keys file '${ssh_authorized_keys_file}' is empty!"
+ fi
+
+ populate_binpkg ${PN}
+
+ mkdir -p "${TDIR}" || gen_die "Failed to create '${TDIR}'!"
+
+ unpack "$(get_gkpkg_binpkg "${PN}")" "${TDIR}"
+
+ if [[ "${SSH_HOST_KEYS}" == 'runtime' ]]
+ then
+ print_info 2 "$(get_indent 2)${PN}: >> No SSH host key embedded due to --ssh-host-key=runtime; Dropbear will generate required host key(s) at runtime!"
+ else
+ if ! hash ssh-keygen &>/dev/null
then
- if /usr/bin/dropbearconvert openssh dropbear /etc/ssh/ssh_host_rsa_key /etc/dropbear/dropbear_rsa_host_key
+ gen_die "'ssh-keygen' program is required but missing!"
+ fi
+
+ local initramfs_dropbear_dir="${TDIR}/etc/dropbear"
+
+ if [[ "${SSH_HOST_KEYS}" == 'create-from-host' ]]
+ then
+ print_info 3 "$(get_indent 2)${PN}: >> Checking for existence of all SSH host keys ..."
+ local missing_ssh_host_keys=no
+
+ if [ ! -f "/etc/ssh/ssh_host_rsa_key" ]
then
- print_info 1 "$(getIndent 2)SSH: >> /etc/ssh/ssh_host_rsa_key converted into /etc/dropbear/dropbear_rsa_host_key"
+ print_info 3 "$(get_indent 2)${PN}: >> SSH host key '/etc/ssh/ssh_host_rsa_key' is missing!"
+ missing_ssh_host_keys=yes
+ fi
+
+ if [ ! -f "/etc/ssh/ssh_host_ecdsa_key" ]
+ then
+ print_info 3 "$(get_indent 2)${PN}: >> SSH host key '/etc/ssh/ssh_host_ecdsa_key' is missing!"
+ missing_ssh_host_keys=yes
+ fi
+
+ if isTrue "${missing_ssh_host_keys}"
+ then
+ # Should only happen when installing a new system ...
+ print_info 3 "$(get_indent 2)${PN}: >> Creating missing SSH host key(s) ..."
+ ssh-keygen -A || gen_die "Failed to generate host's SSH host key(s) using 'ssh-keygen -A'!"
+ fi
+ fi
+
+ local -a required_dropbear_host_keys=(
+ /etc/dropbear/dropbear_ecdsa_host_key
+ /etc/dropbear/dropbear_rsa_host_key
+ )
+
+ local i=0
+ local n_required_dropbear_keys=${#required_dropbear_host_keys[@]}
+ local required_key=
+ while [[ ${i} < ${n_required_dropbear_keys} ]]
+ do
+ required_key=${required_dropbear_host_keys[${i}]}
+ print_info 3 "$(get_indent 2)${PN}: >> Checking for existence of dropbear host key '${required_key}' ..."
+ if [[ -f "${required_key}" ]]
+ then
+ if [[ ! -s "${required_key}" ]]
+ then
+ print_info 1 "$(get_indent 2)${PN}: >> Dropbear host key '${required_key}' exists but is empty; Removing ..."
+ rm "${required_key}" || gen_die "Failed to remove invalid '${required_key}' null byte file!"
+ elif [[ "${SSH_HOST_KEYS}" == 'create-from-host' ]] \
+ && [[ "${required_key}" == *_rsa_* ]] \
+ && [[ "${required_key}" -ot "/etc/ssh/ssh_host_rsa_key" ]]
+ then
+ print_info 1 "$(get_indent 2)${PN}: >> Dropbear host key '${required_key}' exists but is older than '/etc/ssh/ssh_host_rsa_key'; Removing to force update due to --ssh-host-key=create-from-host ..."
+ rm "${required_key}" || gen_die "Failed to remove outdated '${required_key}' file!"
+ elif [[ "${SSH_HOST_KEYS}" == 'create-from-host' ]] \
+ && [[ "${required_key}" == *_ecdsa_* ]] \
+ && [[ "${required_key}" -ot "/etc/ssh/ssh_host_ecdsa_key" ]]
+ then
+ print_info 1 "$(get_indent 2)${PN}: >> Dropbear host key '${required_key}' exists but is older than '/etc/ssh/ssh_host_ecdsa_key'; Removing to force update due to --ssh-host-key=create-from-host ..."
+ rm "${required_key}" || gen_die "Failed to remove outdated '${required_key}' file!"
+ else
+ print_info 3 "$(get_indent 2)${PN}: >> Dropbear host key '${required_key}' exists!"
+ unset required_dropbear_host_keys[${i}]
+ fi
else
- gen_die "RSA host key conversion using dropbearconvert failed"
+ print_info 3 "$(get_indent 2)${PN}: >> Dropbear host key '${required_key}' is missing! Will create ..."
fi
+
+ i=$((i + 1))
+ done
+
+ if [[ ${#required_dropbear_host_keys[@]} -gt 0 ]]
+ then
+ if isTrue "$(can_run_programs_compiled_by_genkernel)"
+ then
+ dropbear_command="${TDIR}/usr/bin/${dropbear_command}"
+ print_info 3 "$(get_indent 2)${PN}: >> Will use '${dropbear_command}' to create missing keys ..."
+ elif hash ${dropbear_command} &>/dev/null
+ then
+ print_info 3 "$(get_indent 2)${PN}: >> Will use existing '${dropbear_command}' program from path to create missing keys ..."
+ else
+ local error_msg="Need to generate '${required_host_keys[*]}' but '${dropbear_command}'"
+ error_msg=" program is missing. Please install net-misc/dropbear and re-run genkernel!"
+ gen_die "${error_msg}"
+ fi
+
+ local missing_key=
+ for missing_key in ${required_dropbear_host_keys[@]}
+ do
+ dropbear_create_key "${missing_key}" "${dropbear_command}"
+
+ # just in case ...
+ if [ -f "${missing_key}" ]
+ then
+ print_info 3 "$(get_indent 2)${PN}: >> Dropbear host key '${missing_key}' successfully created!"
+ else
+ gen_die "Sanity check failed: '${missing_key}' should exist at this stage but does NOT."
+ fi
+ done
else
- if /usr/bin/dropbearkey -t rsa -f /etc/dropbear/dropbear_rsa_host_key -s 4096 > /dev/null
+ print_info 2 "$(get_indent 2)${PN}: >> Using existing dropbear host keys from /etc/dropbear ..."
+ fi
+
+ cp -aL --target-directory "${initramfs_dropbear_dir}" /etc/dropbear/{dropbear_rsa_host_key,dropbear_ecdsa_host_key} \
+ || gen_die "Failed to copy '/etc/dropbear/{dropbear_rsa_host_key,dropbear_ecdsa_host_key}'"
+
+ # Try to show embedded dropbear host key details for security reasons.
+ # We do it that complicated to get common used formats.
+ local -a key_info_files=()
+ local -a missing_key_info_files=()
+
+ local host_key_file= host_key_file_checksum= host_key_info_file=
+ while IFS= read -r -u 3 -d $'\0' host_key_file
+ do
+ host_key_file_checksum=$(sha256sum "${host_key_file}" 2>/dev/null | awk '{print $1}')
+ if [ -z "${host_key_file_checksum}" ]
then
- print_info 1 "$(getIndent 2)SSH: >> New dropbear RSA host key /etc/dropbear/dropbear_rsa_host_key created"
+ gen_die "Failed to generate SHA256 checksum of '${host_key_file}'!"
+ fi
+
+ host_key_info_file="${GK_V_CACHEDIR}/$(basename "${host_key_file}").${host_key_file_checksum:0:10}.info"
+
+ if [ ! -s "${host_key_info_file}" ]
+ then
+ missing_key_info_files+=( ${host_key_info_file} )
else
- gen_die "RSA host key generation using dropbearkey failed"
+ key_info_files+=( ${host_key_info_file} )
+ fi
+ done 3< <(find "${initramfs_dropbear_dir}" -type f -name '*_key' -print0 2>/dev/null)
+ unset host_key_file host_key_file_checksum host_key_info_file
+ IFS="${GK_DEFAULT_IFS}"
+
+ if [[ ${#missing_key_info_files[@]} -ne 0 ]]
+ then
+ dropbear_command=
+ if isTrue "$(can_run_programs_compiled_by_genkernel)"
+ then
+ dropbear_command="${TDIR}/usr/bin/dropbearconvert"
+ print_info 3 "$(get_indent 2)${PN}: >> Will use '${dropbear_command}' to extract embedded host key information ..."
+ elif hash dropbearconvert &>/dev/null
+ then
+ dropbear_command=dropbearconvert
+ print_info 3 "$(get_indent 2)${PN}: >> Will use existing '${dropbear_command}' program to extract embedded host key information ..."
+ else
+ print_warning 2 "$(get_indent 2)${PN}: >> 'dropbearconvert' program not available; Cannot generate missing key information for ${#missing_key_info_files[@]} key(s)!"
+ fi
+
+ if [[ -n "${dropbear_command}" ]]
+ then
+ # We are missing at least information for one embedded key
+ # but looks like we are able to generate the missing information ...
+ local missing_key_info_file=
+ for missing_key_info_file in "${missing_key_info_files[@]}"
+ do
+ dropbear_generate_key_info_file "${dropbear_command}" "${missing_key_info_file}" "${initramfs_dropbear_dir}"
+ key_info_files+=( ${missing_key_info_file} )
+ done
+ unset missing_key_info_file
fi
fi
- fi
- if [ ! -e /etc/dropbear/dropbear_dss_host_key ]
- then
- if /usr/bin/dropbearkey -t dss -f /etc/dropbear/dropbear_dss_host_key > /dev/null
+ if [[ ${#key_info_files[@]} -gt 0 ]]
then
- print_info 1 "$(getIndent 2)SSH: >> New dropbear DSS host key /etc/dropbear/dropbear_dss_host_key created"
+ # We have at least information about one embedded key ...
+ print_info 1 "=================================================================" 1 0 1
+ print_info 1 "This initramfs' sshd will use the following host key(s):" 1 0 1
+
+ local key_info_file=
+ for key_info_file in "${key_info_files[@]}"
+ do
+ print_info 1 "$(cat "${key_info_file}")" 1 0 1
+ done
+ unset key_info_file
+
+ if [ ${LOGLEVEL} -lt 3 ]
+ then
+ # Don't clash with output from log_future_cpio_content
+ print_info 1 "=================================================================" 1 0 1
+ fi
else
- gen_die "DSS host key generation using dropbearkey failed"
+ print_warning 2 "$(get_indent 2)${PN}: >> No information about embedded SSH host key(s) available."
fi
fi
- cd "${TEMP}" \
- || gen_die "cd '${TEMP}' failed"
- mkdir -p ${TEMP}/initramfs-dropbear-temp/var/run
- mkdir -p ${TEMP}/initramfs-dropbear-temp/var/log
- mkdir -p ${TEMP}/initramfs-dropbear-temp/etc/dropbear
- mkdir -p ${TEMP}/initramfs-dropbear-temp/bin
- mkdir -p ${TEMP}/initramfs-dropbear-temp/root/.ssh
+ local libdir=$(get_chost_libdir)
+ mkdir -p "${TDIR}"/lib || gen_die "Failed to create '${TDIR}/lib'!"
+ copy_system_binaries "${TDIR}"/lib "${libdir}"/libnss_files.so.2
- cp -L ${GK_SHARE}/defaults/login-remote.sh ${TEMP}/initramfs-dropbear-temp/bin/ || gen_die "failed to copy defaults/login-remote.sh"
- cp -L /etc/dropbear/{dropbear_rsa_host_key,dropbear_dss_host_key} ${TEMP}/initramfs-dropbear-temp/etc/dropbear/ || gen_die "failed to copy dropbear host key(s)"
- cp -L /etc/dropbear/authorized_keys ${TEMP}/initramfs-dropbear-temp/root/.ssh || gen_die "failed to copy /etc/dropbear/authorized_keys. Did you forget to configure dropbear?"
- cp -L /etc/localtime ${TEMP}/initramfs-dropbear-temp/etc/ || gen_die "failed to copy /etc/localtime. Please set system's timezone!"
- if [ ${ARCH} = "x86_64" ]
- then
- mkdir -p ${TEMP}/initramfs-dropbear-temp/lib64
- cp -L /lib64/libnss_files.so.2 ${TEMP}/initramfs-dropbear-temp/lib64/ || gen_die "failed to copy libnss_files.so.2"
- else
- mkdir -p ${TEMP}/initramfs-dropbear-temp/lib
- cp -L /lib/libnss_files.so.2 ${TEMP}/initramfs-dropbear-temp/lib/ || gen_die "failed to libnss_files.so.2"
- fi
+ cd "${TDIR}" || gen_die "Failed to chdir to '${TDIR}'!"
+
+ cp -a "${GK_SHARE}"/defaults/login-remote.sh "${TDIR}"/usr/bin/ \
+ || gen_die "Failed to copy '${GK_SHARE}/defaults/login-remote.sh'"
+
+ cp -a "${GK_SHARE}"/defaults/resume-boot.sh "${TDIR}"/usr/sbin/resume-boot \
+ || gen_die "Failed to copy '${GK_SHARE}/defaults/resume-boot.sh' to '${TDIR}/usr/sbin/resume-boot'"
+
+ cp -a "${GK_SHARE}"/defaults/unlock-luks.sh "${TDIR}"/usr/sbin/unlock-luks \
+ || gen_die "Failed to copy '${GK_SHARE}/defaults/unlock-luks.sh' to '${TDIR}/usr/sbin/unlock-luks'"
+
+ cp -aL "${ssh_authorized_keys_file}" "${TDIR}"/root/.ssh/ \
+ || gen_die "Failed to copy '${ssh_authorized_keys_file}'!"
+
+ cp -aL /etc/localtime "${TDIR}"/etc/ \
+ || gen_die "Failed to copy '/etc/localtime'. Please set system's timezone!"
- sed "s/compat/files/g" /etc/nsswitch.conf > ${TEMP}/initramfs-dropbear-temp/etc/nsswitch.conf || gen_die "failed to modify /etc/nsswitch.conf"
- echo "root:x:0:0:root:/root:/bin/login-remote.sh" > ${TEMP}/initramfs-dropbear-temp/etc/passwd
- echo "/bin/login-remote.sh" > ${TEMP}/initramfs-dropbear-temp/etc/shells
- echo "root:!:0:0:99999:7:::" > ${TEMP}/initramfs-dropbear-temp/etc/shadow
- echo "root:x:0:root" > ${TEMP}/initramfs-dropbear-temp/etc/group
- echo "" > ${TEMP}/initramfs-dropbear-temp/var/log/lastlog
+ echo "root:x:0:0:root:/root:/usr/bin/login-remote.sh" > "${TDIR}"/etc/passwd \
+ || gen_die "Failed to create '/etc/passwd'!"
- chmod 0755 ${TEMP}/initramfs-dropbear-temp/bin/login-remote.sh
- chmod 0700 ${TEMP}/initramfs-dropbear-temp/root/.ssh
- chmod 0640 ${TEMP}/initramfs-dropbear-temp/etc/shadow
- chmod 0644 ${TEMP}/initramfs-dropbear-temp/etc/passwd
- chmod 0644 ${TEMP}/initramfs-dropbear-temp/etc/group
- mkfifo ${TEMP}/initramfs-dropbear-temp/etc/dropbear/fifo_root
- mkfifo ${TEMP}/initramfs-dropbear-temp/etc/dropbear/fifo_swap
+ echo "/usr/bin/login-remote.sh" > "${TDIR}"/etc/shells \
+ || gen_die "Failed to create '/etc/shells'!"
- copy_binaries "${TEMP}"/initramfs-dropbear-temp/ /usr/sbin/dropbear \
- /bin/login /usr/bin/passwd
+ echo "root:!:0:0:99999:7:::" > "${TDIR}"/etc/shadow \
+ || gen_die "Failed to create '/etc/shadow'!"
+ echo "root:x:0:root" > "${TDIR}"/etc/group \
+ || gen_die "Failed to create '/etc/group'!"
+
+ chmod 0755 "${TDIR}"/usr/bin/login-remote.sh \
+ || gen_die "Failed to chmod of '${TDIR}/usr/bin/login-remote.sh'!"
+
+ chmod 0755 "${TDIR}"/usr/sbin/resume-boot \
+ || gen_die "Failed to chmod of '${TDIR}/usr/sbin/resume-boot'!"
+
+ chmod 0755 "${TDIR}"/usr/sbin/unlock-luks \
+ || gen_die "Failed to chmod of '${TDIR}/usr/sbin/unlock-luks'!"
+
+ chmod 0640 "${TDIR}"/etc/shadow \
+ || gen_die "Failed to chmod of '${TDIR}/etc/shadow'!"
+
+ chmod 0644 "${TDIR}"/etc/passwd \
+ || gen_die "Failed to chmod of '${TDIR}/etc/passwd'!"
+
+ chmod 0644 "${TDIR}"/etc/group \
+ || gen_die "Failed to chmod of '${TDIR}/etc/group'!"
+
+ cd "${TDIR}" || gen_die "Failed to chdir to '${TDIR}'!"
log_future_cpio_content
- cd "${TEMP}"/initramfs-dropbear-temp \
- || gen_die "cd '${TEMP}/initramfs-dropbear-temp' failed"
- find . -print | cpio ${CPIO_ARGS} --append -F "${CPIO}"
- rm -rf "${TEMP}"/initramfs-dropbear-temp > /dev/null
+
+ find . -print | cpio ${CPIO_ARGS} --append -F "${CPIO}" \
+ || gen_die "Failed to append ${PN} to cpio!"
}
append_firmware() {
diff --git a/genkernel b/genkernel
index 3c9d0e7..25dc7f5 100755
--- a/genkernel
+++ b/genkernel
@@ -397,6 +397,7 @@ then
isTrue "${DMRAID}" && print_warning 1 '- Add "dodmraid" for dmraid support or "dodmraid=<additional options>"'
isTrue "${MDADM}" && print_warning 1 '- Add "domdadm" for MDRAID support'
isTrue "${LVM}" && print_warning 1 '- Add "dolvm" for LVM support'
+ isTrue "${SSH}" && print_warning 1 '- Add "dosshd" to start SSH daemon in initramfs'
if isTrue "${ZFS}"
then
diff --git a/gkbuilds/dropbear.gkbuild b/gkbuilds/dropbear.gkbuild
new file mode 100644
index 0000000..e6a43f6
--- /dev/null
+++ b/gkbuilds/dropbear.gkbuild
@@ -0,0 +1,68 @@
+# Copyright 1999-2019 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+src_prepare() {
+ default
+
+ # Disable DSS support
+ echo "#define DROPBEAR_DSS 0" > localoptions.h || die "Failed to disable DSS support"
+}
+
+src_configure() {
+ local myconf=(
+ --enable-static
+ --disable-pam
+ --disable-syslog
+ --with-zlib="${BROOT}/usr"
+ )
+
+ gkconf "${myconf[@]}"
+}
+
+src_compile() {
+ local MYMAKEOPTS=( "V=1" )
+ MYMAKEOPTS+=( "MULTI=1" )
+ MYMAKEOPTS+=( "PROGRAMS='dropbear dropbearkey dropbearconvert scp'" )
+ gkmake "${MYMAKEOPTS[@]}"
+}
+
+src_install() {
+ local mydir=
+ for mydir in \
+ etc/dropbear \
+ usr/bin \
+ usr/sbin \
+ root/.ssh \
+ var/log \
+ var/run \
+ ; do
+ mkdir -p "${D}"/${mydir} || die "Failed to create '${D}/${mydir}'!"
+ done
+
+ cp -a dropbearmulti "${D}"/usr/bin/ \
+ || die "Failed to copy '${S}/dropbearmulti' to '${D}/usr/bin/'!"
+
+ "${STRIP}" --strip-all "${D}"/usr/bin/dropbearmulti \
+ || die "Failed to strip '${D}/usr/bin/dropbearmulti'!"
+
+ ln -s ../bin/dropbearmulti "${D}"/usr/sbin/dropbear \
+ || die "Failed to symlink '${D}/usr/sbin/dropbear' to '${D}/usr/bin/dropbearmulti'!"
+
+ ln -s dropbearmulti "${D}"/usr/bin/dropbearconvert \
+ || die "Failed to symlink '${D}/usr/bin/dropbearconvert' to '${D}/usr/bin/dropbearmulti'!"
+
+ ln -s dropbearmulti "${D}"/usr/bin/dropbearkey \
+ || die "Failed to symlink '${D}/usr/bin/dropbearkey' to '${D}/usr/bin/dropbearmulti'!"
+
+ ln -s dropbearmulti "${D}"/usr/bin/scp \
+ || die "Failed to symlink '${D}/usr/bin/scp' to '${D}/usr/bin/dropbearmulti'!"
+
+ chmod 0700 "${D}"/root/.ssh \
+ || die "Failed to chmod of '${D}/root/.ssh'!"
+
+ mkfifo "${D}"/etc/dropbear/fifo_root \
+ || die "Failed to create '${D}/etc/dropbear/fifo_root'!"
+
+ mkfifo "${D}"/etc/dropbear/fifo_swap \
+ || die "Failed to create '${D}/etc/dropbear/fifo_swap'!"
+}