#!/bin/bash # Guide: https://rr-developer.github.io/LUKS-on-Raspberry-Pi/ plus others # # This script can be run two different ways: # * Automatically by sdm on the booted system as invoked by the cryptroot plugin via the sdm-auto-encrypt service # * Manually on the booted system # function errexit() { cryptolog "$1" noconsole echo -e "$1" exit 1 } function thisdate() { echo "$(date +"$datefmt")" } function wait_startup_complete { # $1 is the message to write local lc=0 msg=$1 while [[ "$(systemctl show -p ActiveState graphical.target --value)" != "active" ]] && [[ "$(systemctl show -p ActiveState multi-user.target --value)" != "active" ]] do if [ $lc -eq 0 ] then logger "$msg" echo "$msg" > /dev/console lc=1 fi sleep 1 done } function getgbstr() { # # $1: # of bytes in partition # # Returns the string "(nn.nnGB, mm.mmGiB)" local nbytes=$1 local gb=1000000000 gib=1073741824 gb2=500000000 gi2=536870912 local ngbytes ngibytes ngbytes=$(printf %.1f "$(( ((10 * nbytes)+gb2) / gb ))e-1") ngibytes=$(printf %.1f "$(( ((10 * nbytes)+gi2) / gib))e-1") echo "(${ngbytes}GB, ${ngibytes}GiB)" return } function getfsdf() { # # $1: fs name # $2: df component: pcent, avail, etc # echo "$(df --output=$2 $1 | tail -1 | (IFS="%" ; read a ; a="${a% }" ; a="${a# }" echo $a))" } function ispdevp() { local dev="$1" [[ "$dev" =~ "mmcblk" ]] || [[ "$dev" =~ "nvme0n1" ]] && return 0 || return 1 } function getspname() { local dev="$1" pn="$2" ispdevp $dev && echo "${dev}p${pn}" || echo "${dev}${pn}" } function getpartname() { local dev="$1" pn="$2" ispdevp $dev && echo "p${pn}" || echo "$pn" } function cryptolog() { local msg="$1" opts="$2" datefmt="%Y-%m-%d %H:%M:%S" pfx="sdm-cryptconfig:" msgc [[ "$msg" =~ "sdm-cryptconfig:" ]] && msgc="$msg" || msgc="$pfx $msg" if [ $xsdm -eq 1 ] then [[ "$opts" =~ "noconsole" ]] || echo "$msgc" > /dev/console else [ "$msg" == "" ] && echo "$msg" > /dev/tty || echo "> $msg" > /dev/tty fi [ -f /etc/sdm/history ] && echo "$(thisdate) sdm-cryptconfig: $msg" >> /etc/sdm/history } function checknumeric() { # # Exit with error if $1 is not numeric # [[ "$1" = *[^0-9]* ]] && errexit "? Value '$1' for command switch '$2' is not numeric" return } function iswifienabled() { # Look for any wireless interface (wlan*, wlp*, etc) for iface in /sys/class/net/w* do [ -d $iface/wireless ] && return 0 done return 1 } function askyn() { local ans echo -n "$1" '[y/n]? ' ; read $2 ans case "$ans" in y*|Y*) return 0 ;; *) return 1 ;; esac } function ispkginstalled() { # # $1 has package name # iver=$(apt-cache policy $1 | grep Installed: 2> /dev/null) if [ "$iver" == "" ] then return 1 else [[ "$iver" =~ "(none)" ]] && return 1 || return 0 fi return } function installpkgsif() { local pkglist="$1" pkgs=() newpkgs="" p IFS=" " read -a pkgs <<< $pkglist for p in "${pkgs[@]}" do ispkginstalled $p && cryptolog " Package '$p' is already installed" noconsole || newpkgs="$newpkgs $p" done [ "$newpkgs" == "" ] || apt-get install --no-install-recommends --yes $newpkgs } function getphrase() { local pprompt="$1" local phrase phrase2 silent="-s" #silent="" while [ true ] do while [ true ] do read $silent -p "${pprompt}: " phrase [ "$silent" != "" ] && echo "" >/dev/tty [ "phrase" == "" ] || break done while [ true ] do read $silent -p "Retype ${pprompt}: " phrase2 [ "$silent" != "" ] && echo "" >/dev/tty [ "$phrase2" == "" ] || break done [ "$phrase" == "$phrase2" ] && break echo "% Phrases do not match; try again" >/dev/tty done echo "$phrase" } function printhelp() { echo $" sdm-cryptconfig has several command line switches, all of which are optional * --authorized-keys keyfile -- Provides SSH authorized_keys file for the initramfs. Required with --ssh * --crypto cryptalgo -- Specify crypto algorithm (aes [D]) or xchacha (use on Pi4 and earlier) * --dns dnsaddr -- Set IP Address of DNS server * --gateway gatewayaddr -- Set IP address of gateway * --hostname hostname -- Set hostname * --ipaddr ipaddr -- set IP address to use in initramfs * --keyfile keyfile -- Key file for USB-based key unlock * --mapper cryptmapname -- Set cryptroot mapper name [Default: cryptroot] * --mask netmask -- Set network mask for initramfs * --no-expand-root -- Don't expand rootfs after rootfs encryption has completed * --no-last-reboot -- Don't do final reboot after sdm-cryptfs-cleanup * --nopwd -- No password on encrypted rootfs; keyfile (required) is only unlock * --quiet -- Do not disable quiet boot for RasPiOS with desktop * --reboot -- Reboot the system (into initramfs) when sdm-cryptconfig is complete * --sdm -- sdm cryptroot plugin sets this * --ssh -- Enable SSH in initramfs * --sshbash -- Leave ssh session bash enabled [Default: use cryptroot-unlock] * --sshport port -- Specify initramfs SSH port [Default: 22] * --sshtimeout timeout -- Specify initramfs SSH timeout [Default: 3600] * --tries n -- Specify number of unlock tries before giving up [Default: 0 (infinite)] * --unique-ssh -- Use a different SSH host key in initramfs than the host OS SSH key * --wifi-password -- Specify WiFi password for the WiFi connection * --wifi-ssid -- Enable WiFi in initramfs and specify the WiFi SSID for connection (Requires --ssh, --authorized-keys, and --wifi-password) * --wifi-use-psk -- Convert WiFi password to a WPA PSK in wpa_supplicant.conf The network configuration switches (dns, gateway, hostname, ipaddr, and mask) are only needed and should only be used if you know that the system is unable to get an IP address and network configuration information from the network (e.g., via DHCP). These settings are ONLY used in the initramfs if SSH is enabled and are not automatically removed, so each time the system restarts the initramfs will use these settings. " } function printinfo() { local used1k usedby usedstr rootfs sd rootfs=$(findmnt --noheadings --output source /) # rootfs name sd=${rootfs%$(getpartname $rootfs 2)} # dev name w/o partition name used1k=$(getfsdf "/" used) usedby=$((used1k*1024)) usedstr=$(getgbstr $usedby) cryptolog "" noconsole cryptolog "Rootfs '$rootfs' has $usedby bytes $usedstr used" noconsole cryptolog "" noconsole cryptolog "You will need another disk for the encryption process to use as a scratch disk" noconsole cryptolog " This disk must be larger than $usedstr and it will be over-written" noconsole cryptolog "" noconsole cryptolog $"Reboot the system when you are ready to continue The system will start to reboot, but hang trying to read rootfs. It will try 30 times before giving up and dropping to the initramfs prompt: (initramfs) ** Ignore the 'ALERT! missing /dev/mapper' message. That is expected. ** Once at the (initramfs) prompt, connect the SSD or SD Card that will be used as a scratch drive When you have the drive name enter the command: (initramfs) sdmcryptfs $sd /dev/sdX Where: $sd is the name of your system disk /dev/sdX is the name of your scratch disk sdmcryptfs will: * Print the size of rootfs $rootfs * Save the contents of $rootfs to /dev/sdX * NOTE: There will be no prompts for passphrases if --nopwd specified * Enable encryption on $rootfs * You will be prompted to enter YES (all in upper case) to continue * You will then be prompted to provide the passphrase for $rootfs (unless --nopwd) ** Be sure that your CapsLock is set correctly (in case you changed it to type YES)!!! ** * After a short pause you'll be prompted for the passphrase again to unlock $rootfs (unless --nopwd) * The saved rootfs content will be restored from /dev/sdX to the encrypted rootfs * When the restore finishes sdmcryptfs will exit and drop you to the (initramfs) prompt * Type 'exit' to continue the boot sequence * Once the system boots the sdm-cryptfs-cleanup service will run which: * Removes some one-time content and rebuilds initramfs * Reboots the system one last time " noconsole if [ $xnopwd -eq 0 ] then cryptolog $"As the system reboots you'll once again be prompted for the rootfs passphrase (Without the 30 tries) ** The system will now ask for the rootfs passphrase like this every time the system boots ** " noconsole else cryptolog $"As the system reboots it will hang until the USB keyfile disk is found in a USB drive " noconsole fi if [ $xssh -eq 1 ] then cryptolog $" NOTE: You have configured SSH Please review https://github.com/gitbls/sdm/blob/master/Docs/Disk-Encryption.md " noconsole fi } function wifimakewpa() { local pwd="$1" hashed=$2 psks cryptolog "Create wpa_supplicant config for WiFi in initramfs" noconsole mkdir -p /etc/wpa_supplicant [ "$hashed" == "" ] && psks="psk\"$pwd\"" || psks="psk=$pwd" cat > /etc/wpa_supplicant/wpa_supplicant-luks.conf << EOF ctrl_interface=/run/wpa_supplicant update_config=1 network={ ssid="$xwifissid" $psks scan_ssid=1 } EOF chmod 600 /etc/wpa_supplicant/wpa_supplicant-luks.conf } function wificonfiginitramfs() { cryptolog "Create WiFi initramfs hook /etc/initramfs-tools/hooks/sdm-enable-wifi" noconsole cat > /etc/initramfs-tools/hooks/sdm-enable-wifi << 'EOF' #!/bin/sh set -e PREREQ="" prereqs() { echo "${PREREQ}" } case "${1}" in prereqs) prereqs exit 0 ;; esac . /usr/share/initramfs-tools/hook-functions # Add the wireless modules manual_add_modules brcmfmac manual_add_modules brcmfmac-wcc # Copy wpa_supplicant binaries copy_exec /sbin/wpa_supplicant copy_exec /sbin/wpa_cli # Copy rfkill to unblock WiFi radio copy_exec /usr/sbin/rfkill # Copy wpa_supplicant config mkdir -p ${DESTDIR}/etc/wpa_supplicant cp /etc/wpa_supplicant/wpa_supplicant-luks.conf ${DESTDIR}/etc/wpa_supplicant/wpa_supplicant.conf # Copy Broadcom firmware (copy actual files, not symlinks) mkdir -p ${DESTDIR}/usr/lib/firmware/brcm mkdir -p ${DESTDIR}/usr/lib/firmware/cypress # Copy the actual cyfmac files cp /lib/firmware/cypress/cyfmac43455-sdio-standard.bin ${DESTDIR}/usr/lib/firmware/cypress/cyfmac43455-sdio.bin cp /lib/firmware/cypress/cyfmac43455-sdio.clm_blob ${DESTDIR}/usr/lib/firmware/cypress/ # Copy all the brcm files, following symlinks to get actual content cd /lib/firmware/brcm for file in *43455*; do if [ -e "$file" ]; then cp -L "$file" ${DESTDIR}/usr/lib/firmware/brcm/ 2>/dev/null || true fi done # Copy regulatory database (follow symlinks to get actual files) cp -L /lib/firmware/regulatory.db ${DESTDIR}/usr/lib/firmware/regulatory.db 2>/dev/null || \ cp /lib/firmware/regulatory.db-debian ${DESTDIR}/usr/lib/firmware/regulatory.db cp -L /lib/firmware/regulatory.db.p7s ${DESTDIR}/usr/lib/firmware/regulatory.db.p7s 2>/dev/null || \ cp /lib/firmware/regulatory.db.p7s-debian ${DESTDIR}/usr/lib/firmware/regulatory.db.p7s EOF chmod 755 /etc/initramfs-tools/hooks/sdm-enable-wifi # Create init-premount script cryptolog "Create WiFi initramfs init-premount script /etc/initramfs-tools/scripts/init-premount/sdm-premount-enable-wifi" noconsole cat > /etc/initramfs-tools/scripts/init-premount/sdm-premount-enable-wifi << 'EOF' #!/bin/sh PREREQ="" prereqs() { echo "$PREREQ" } case $1 in prereqs) prereqs exit 0 ;; esac . /scripts/functions # Load the wireless module explicitly log_begin_msg "Loading brcmfmac module" modprobe brcmfmac log_end_msg # Wait for wireless interface to appear (with timeout) log_begin_msg "Waiting for wireless interface" TIMEOUT=10 COUNTER=0 WLAN_INTERFACE="" while [ $COUNTER -lt $TIMEOUT ]; do # Look for any wireless interface (wlan*, wlp*, etc) for iface in /sys/class/net/w*; do if [ -d "$iface/wireless" ]; then WLAN_INTERFACE=$(basename "$iface") break 2 fi done # Also check specifically for wlan0 if [ -d "/sys/class/net/wlan0" ]; then WLAN_INTERFACE="wlan0" break fi sleep 1 COUNTER=$((COUNTER + 1)) done log_end_msg if [ -z "$WLAN_INTERFACE" ]; then log_failure_msg "No wireless interface found after ${TIMEOUT} seconds" # Don't panic - allow boot to continue (ethernet might work) exit 0 fi log_success_msg "Found wireless interface: ${WLAN_INTERFACE}" # Unblock WiFi radio (RF-kill) log_begin_msg "Unblocking WiFi radio" rfkill unblock wifi 2>/dev/null || true rfkill unblock all 2>/dev/null || true log_end_msg # Bring interface up log_begin_msg "Bring up ${WLAN_INTERFACE}" ip link set ${WLAN_INTERFACE} up sleep 2 log_end_msg # Start wpa_supplicant log_begin_msg "Starting wpa_supplicant on ${WLAN_INTERFACE}" mkdir -p /run/wpa_supplicant /sbin/wpa_supplicant -i${WLAN_INTERFACE} -c/etc/wpa_supplicant/wpa_supplicant.conf -P/run/initram-wpa_supplicant.pid -B -f /tmp/wpa_supplicant.log -C/run/wpa_supplicant sleep 3 log_end_msg # Wait for connection (with timeout) log_begin_msg "Waiting for WiFi association" TIMEOUT=30 COUNTER=0 CONNECTED=0 while [ $COUNTER -lt $TIMEOUT ]; do if /sbin/wpa_cli -p/run/wpa_supplicant status 2>/dev/null | grep -q "wpa_state=COMPLETED"; then CONNECTED=1 break fi sleep 1 COUNTER=$((COUNTER + 1)) done if [ $CONNECTED -eq 1 ]; then log_success_msg "WiFi connected" # Configure IP address log_begin_msg "Configuring IP address via DHCP" ipconfig -t 10 ${WLAN_INTERFACE} log_end_msg else log_failure_msg "WiFi connection failed after ${TIMEOUT} seconds" fi exit 0 EOF chmod 755 /etc/initramfs-tools/scripts/init-premount/sdm-premount-enable-wifi # Create local-bottom script to kill wpa_supplicant cryptolog "Create WiFi initramfs local-bottom cleanup script /etc/initramfs-tools/scripts/local-bottom/sdm-kill-wireless" noconsole cat > /etc/initramfs-tools/scripts/local-bottom/sdm-kill-wireless << 'EOF' #!/bin/sh PREREQ="" prereqs() { echo "$PREREQ" } case $1 in prereqs) prereqs exit 0 ;; esac echo "Killing wpa_supplicant so the system takes over later." if [ -f /run/initram-wpa_supplicant.pid ]; then kill $(cat /run/initram-wpa_supplicant.pid) 2>/dev/null || true fi EOF chmod 755 /etc/initramfs-tools/scripts/local-bottom/sdm-kill-wireless } function configcleanupsvc() { # # Set up service to run after next reboot that will rebuild initramfs (again) and reboot # cryptolog "Configure run-once service to cleanup and rebuild initramfs after rootfs encryption completes and boots" noconsole cat > /etc/systemd/system/sdm-cryptfs-cleanup.service < /usr/local/bin/sdm-cryptfs-cleanup <<'EOF' #!/bin/bash function wait_startup_complete() { # $1 is the message to write local lc=0 msg=$1 while [[ "$(systemctl show -p ActiveState graphical.target --value)" != "active" ]] && [[ "$(systemctl show -p ActiveState multi-user.target --value)" != "active" ]] do if [ $lc -eq 0 ] then logger "$msg" echo "$msg" > /dev/console lc=1 fi sleep 1 done } function thisdate() { local datefmt="%Y-%m-%d %H:%M:%S" echo "$(date +"$datefmt")" } function echolog() { local msg="$1" echo "$msg" >/dev/console logger "$msg" [ -f /etc/sdm/history ] && echo "$(thisdate) $msg" >> /etc/sdm/history } echolog "sdm-cryptfs-cleanup: Starting; System will restart automatically when completed" echolog "sdm-cryptfs-cleanup: Clean up initramfs content" mv /etc/initramfs-tools/hooks/luks-hooks /etc/initramfs-tools/hooks/.sdm.luks-hooks.old # Leave bash in initramfs as required by sdmluksunlock grep -v -E "sdmcryptfs|mapper|lz4|sgdisk|/etc/sdm/assets/cryptroot" /etc/initramfs-tools/hooks/.sdm.luks-hooks.old > /etc/initramfs-tools/hooks/luks-hooks chmod 755 /etc/initramfs-tools/hooks/luks-hooks grep -q -s xsshbash:0 /etc/sdmcryptctl && [ -f /etc/dropbear/initramfs/dropbear.conf ] && sed -i "s/bash/cryptroot-unlock/" /etc/dropbear/initramfs/dropbear.conf rm -f /etc/sdm/assets/cryptroot/*.lek /etc/*.lek echolog "sdm-cryptfs-cleanup: Rebuild initramfs" update-initramfs -u if grep -q -s xsdm:1 /etc/sdmcryptctl then [ -f /etc/sdm/sdm-readparams ] && source /etc/sdm/sdm-readparams || echolog "% sdm-cryptfs-cleanup: Unable to find expected /etc/sdm/sdm-readparams" [ -f /etc/sdm/assets/cryptbbh ] && { cat /etc/sdm/assets/cryptbbh >| /etc/sdm/assets/gfxbbh && do_delayed_boot_behavior reboot ; } || echolog "% sdm-cryptfs-cleanup: /etc/sdm/assets/cryptbbh not found; Boot behavior setting may not be correct" else if grep -q -s graphical.target /etc/sdmcryptctl then echolog "sdm-cryptfs-cleanup: Reset systemctl default target to graphical.target" systemctl set-default graphical.target # Don't enable these services since no 'splash' in cmdline.txt (see below) # if grep -q -s clsplash /etc/sdmcryptctl # then # for svc in plymouth-start plymouth-read-write plymouth-quit-wait # plymouth-reboot plymouth-quit # do # echolog "sdm-cryptfs-cleanup: Unmask service '$svc'" # systemctl unmask $svc >/dev/null 2>&1 # done # fi fi if grep -s -q xquiet:0 /etc/sdmcryptctl then if grep -q -s clquiet /etc/sdmcryptctl then echolog "sdm-cryptfs-cleanup: Reset 'quiet' in cmdline.txt" sed -i "s/rootwait/rootwait quiet/g" /boot/firmware/cmdline.txt fi # 'splash' in cmdline.txt prevents booting after sdm-cryptfs-cleanup reboots (? because prompt to unlock disk is lost/hidden?) # if grep -q -s clsplash /etc/sdmcryptctl # then # echolog "sdm-cryptfs-cleanup: Reset 'splash' in cmdline.txt" # sed -i "s/rootwait/rootwait splash/g" /boot/firmware/cmdline.txt # fi fi fi if grep -q -s re-enable-tty1 /etc/sdmcryptctl then echolog "sdm-cryptfs-cleanup: Re-enable getty@tty1" systemctl -q enable getty@tty1 fi systemctl disable sdm-cryptfs-cleanup rm -f /etc/systemd/system/sdm-cryptfs-cleanup.service rm -f /etc/systemd/system/sdm-auto-encrypt.service systemctl daemon-reload wait_startup_complete "sdm-cryptfs-cleanup: Wait for system startup to complete" rm -f /etc/sdm/control/rootfs-encryption if grep -q -s xnolastrb:0 /etc/sdmcryptctl then secs=5 echolog "sdm-cryptfs-cleanup: The system will restart in $secs seconds" sleep $secs echolog "sdm-cryptfs-cleanup: System restarting now" #rm -f /usr/local/bin/sdm-cryptfs-cleanup sleep 2 reboot else echolog "sdm-cryptfs-cleanup: Complete" exit 0 fi EOF chmod 755 /usr/local/bin/sdm-cryptfs-cleanup pgrep systemd >/dev/null 2>&1 && cryptolog " (Ignore any RequiresMountsFor errors in the system journal)" noconsole && systemctl daemon-reload systemctl enable sdm-cryptfs-cleanup > /dev/null 2>&1 } function parsecmd() { local cmd="$1" args="$2" local longopts="authorized-keys:,crypto:,debug,dns:,gateway:,help,hostname:,ipaddr:,keyfile:,mapper:,mask:,netmask:,no-expand-root,no-last-reboot,nopwd,ssh,sshbash,sshport:,sshtimeout:,reboot,sdm,tries:,unique-ssh,wifi-ssid:,wifi-password:,wifi-use-psk" OARGS=$(getopt -o h --longoptions $longopts -n 'sdm' -- "$@") [ $? -ne 0 ] && errexit "? $cmd: Unable to parse command" eval set -- "$OARGS" while true do case "${1,,}" in # 'shift 2' if switch has argument, else just 'shift' --authorized-keys) xauthkeys=$2 ; shift 2 ;; --crypto) xcrypto=$2 ; shift 2 ;; --debug) xdebug=1 ; shift 1 ;; --dns) xdns=$2 ; shift 2 ;; --gateway) xgateway=$2 ; shift 2 ;; --hostname) xhostname=$2 ; shift 2 ;; --ipaddr) xipaddr=$2 ; shift 2 ;; --keyfile) xkeyfile=$2 ; shift 2 ;; --mapper) xmapper=$2 ; shift 2 ;; --mask|--netmask) xnetmask=$2 ; shift 2 ;; --no-expand-root) xnoexpand=1 ; shift 1 ;; --no-last-reboot) xnolastrb=1 ; shift 1 ;; --nopwd) xnopwd=1 ; shift 1 ;; --quiet) xquiet=1 ; shift 1 ;; --reboot) xreboot=1 ; shift 1 ;; --ssh) xssh=1 ; shift 1 ;; --sshbash) xsshbash=1 ; shift 1 ;; --sshport) xsshport=$2 ; shift 2 ;; --sshtimeout) xsshtimeout=$2 ; shift 2 ;; --sdm) xsdm=1 ; shift 1 ;; --tries) xtries=$2 ; shift 2 ;; --unique-ssh) xunique=1 ; shift 1 ;; --wifi-ssid) xwifissid="$2" ; shift 2 ;; --wifi-password) xwifipwd="$2" ; shift 2 ;; --wifi-use-psk) xwifipsk=1 ; shift 1 ;; --) shift ; break ;; -h|--help) printhelp ; shift ; exit ;; *) errexit "? $0: Internal error" ;; esac done if [ "$xauthkeys" != "" ] then ! [ -f $xauthkeys ] && errexit "? --authorized-keys file '$xauthkeys' not found" else [ $xssh -eq 1 ] && errexit "? --ssh requires --authorized-keys" fi [[ $xnopwd -eq 1 ]] && [[ "$xkeyfile" == "" ]] && errexit "? --nopwd requires --keyfile" [[ "$xtries" != "" ]] && checknumeric $xtries "--tries" } function doconfiginitramfs() { local kcmd="" knopwd="" # These both need to be set on initramfs-tools 0.142+rpt1 and earlier. This assumes OK. Remove uncommented line for earlier initramfs-tools cryptolog "Update initramfs configuration for 'MODULES=most' and 'update_initramfs=all'" noconsole sed -i "s/^MODULES=dep/MODULES=most/" /etc/initramfs-tools/initramfs.conf #* sed -i "s/^update_initramfs=yes/update_initramfs=all/" /etc/initramfs-tools/update-initramfs.conf cryptolog "Create /usr/bin/sdmluksunlock; runs in initramfs to unlock rootfs" noconsole cat > /usr/bin/sdmluksunlock <<'EOF' #!/bin/bash # # called when it's time to read the LUKS unlock key, which is echoed to stdout/read by caller # function pmsg() { echo "$1" >/dev/console } trydisks() { pmsg "" pmsg "> sdmluksunlock: Looking for USB disk with luks Key file '${kfn}'" pmsg "" while :; do sleep 1 while read usbpartition do usbdevice=$(readlink -f $usbpartition) if mount $usbdevice /mnt 2>/dev/null then #pmsg "> Mounted disk $usbdevice" if [ -e /mnt/$kfn ] then #pmsg "> Found Key file '$kfn'" pmsg "> Unlocking rootfs" cat /mnt/$kfn #cat to sdmluksunlock caller for unlock umount $usbdevice >/dev/null 2>&1 || continue #pmsg "> sdmluksunlock: Kill askpass; Ignore 'Killed' message" aps=$(ps e | grep askpass | grep -v grep | awk '{print $1}') [ "$aps" != "" ] && kill -KILL $aps >/dev/null 2>/dev/null exit else #pmsg "% sdmluksunlock: Key '${kfn%.lek}' not found on this disk" umount $usbdevice >/dev/null 2>&1 || continue fi else #pmsg "% sdmluksunlock: This disk does not have a vfat partition" umount $usbdevice >/dev/null 2>&1 || continue fi done < <(compgen -G "/dev/disk/by-id/usb-*-part1") done return 0 } set -e mkdir -p /mnt if [ "$CRYPTTAB_KEY" != "" ] then kfn=$(basename $CRYPTTAB_KEY) kfn=${kfn%.lek}.lek fi if [[ "$kfn" != "" ]] then if [[ "$2" == "trydisks" ]] then touch /tmp/ftrydisk trydisks exit else [ ! -f /tmp/ftrydisk ] && ( sdmluksunlock $CRYPTTAB_KEY trydisks /dev/null 2>/dev/null exit EOF chmod 755 /usr/bin/sdmluksunlock cryptolog "Create /etc/initramfs-tools/hooks/luks-hooks" noconsole [ "$xkeyfile" != "" ] && kcmd="copy_file text /etc/sdm/assets/cryptroot/$xkeyfile /etc/$xkeyfile" # can't use quoted EOF here cat > /etc/initramfs-tools/hooks/luks-hooks <> /etc/initramfs-tools/modules <> /etc/initramfs-tools/modules <> /etc/initramfs-tools/initramfs.conf fi # # Configure dropbear if requested # if [ $xssh -eq 1 ] then cryptolog "Configure SSH" noconsole sed -i "s#\#DROPBEAR_OPTIONS=\"\"#DROPBEAR_OPTIONS=\"-I $xsshtimeout -j -k -s -p $xsshport -c bash -r /etc/dropbear/dropbear_ed25519_host_key\"#" /etc/dropbear/initramfs/dropbear.conf cryptolog "Copy authorized keys file from '$xauthkeys'" noconsole cp $xauthkeys /etc/dropbear/initramfs/authorized_keys if [ $xunique -eq 0 ] then cryptolog "Convert openSSH host key for use in dropbear/initramfs" noconsole dropbearconvert openssh dropbear /etc/ssh/ssh_host_ed25519_key /etc/dropbear/initramfs/dropbear_ed25519_host_key else cryptolog "Use unique SSH host key in dropbear/initramfs" noconsole fi fi } function domkinitramfs() { cryptolog "Update initramfs with all the rootfs encryption settings in place" noconsole update-initramfs -u } function doupdateconfig() { local rootfs kfu="" kfuuid="none" ktries="" rootfs=$(findmnt --noheadings --output source /) cryptolog "Update root statement in cmdline.txt" noconsole sed -i "s#root=[0-9a-zA-Z-]*[ =][0-9a-zA-Z-]* #root=/dev/mapper/$xmapper #" /boot/firmware/cmdline.txt cryptolog "Add cryptdevice '$xmapper' to cmdline.txt" noconsole # 'rw' needed so crypt device is mounted read/write # luks.crypttab prevents systemd-cryptsetup-generator for reading crypttab sed -i "s# rw cryptdevice=$rootfs:$xmapper luks.crypttab=no##g" /boot/firmware/cmdline.txt # Delete in case sed -i "s#\$# rw cryptdevice=$rootfs:$xmapper luks.crypttab=no#" /boot/firmware/cmdline.txt # mask the service in case other partitions encrypted; this will prevent systemd-cryptsetup errors in journal wrt already-mounted rootfs systemctl -q mask systemd-cryptsetup@$xmapper.service 2>/dev/null cryptolog "Updated cmdline:" noconsole cryptolog " $(cat /boot/firmware/cmdline.txt)" noconsole cryptolog "Update /etc/fstab for the encrypted rootfs" noconsole sed -i "s#PARTUUID=[0-9a-zA-Z-]* */ #/dev/mapper/$xmapper / #" /etc/fstab cryptolog "Update /etc/crypttab" noconsole if [ "$xkeyfile" != "" ] then kfuuid=$(basename $xkeyfile) kfuuid=${kfuuid%.lek} kfu=",keyscript=/usr/bin/sdmluksunlock" ktries=",tries=$xtries" fi # noauto prevents systemd-cryptsetup from touching it. Only needed for rootfs echo "$xmapper $rootfs $kfuuid luks,noauto,discard${ktries}${kfu}" >> /etc/crypttab } # # Main code # [[ ! $EUID -eq 0 ]] && errexit "? Please run as root: sudo $0 $*" xauthkeys="" xcrypto="" xdebug=0 xdns="" xgateway="" xhostname="" xipaddr="" xkeyfile="" xmapper="" xnetmask="" xnoexpand=0 xnolastrb=0 xnopwd=0 xquiet=0 xreboot=0 xsdm=0 xssh=0 xsshbash=0 xsshport="22" xsshtimeout="3600" xtries="0" xunique=0 xwifi=0 xwifissid="" xwifipwd="" xwifipsk=0 src=$(dirname "$(realpath "$0")") parsecmd $0 "$@" [ $xreboot -eq 1 ] && cryptolog "Starting; System will restart automatically when complete" || cryptolog "Starting" cryptolog "Command: $0 $*" noconsole [ "$xmapper" == "" ] && xmapper="cryptroot" [ "$xcrypto" == "" ] && xcrypto="aes" if [ "$xwifissid" != "" ] then iswifienabled || errexit "? WiFi must be enabled on this system to support WiFi initramfs configuration" [ $xssh -eq 0 ] && errexit "? --wifi-ssid requires --ssh and --authorized-keys" [ "$xwifipwd" == "" ] && xwifipwd="$(getphrase "WiFi password for '$xwifissid'")" #askyn "Use this WiFi password: '$xwifipwd'" || errexit "? Exit per user request" xwifi=1 fi [[ "aes|xchacha" =~ $xcrypto ]] || [[ "$xcrypto" =~ aes- ]] || errexit "? Unrecognized crypto '$xcrypto'; Supported --crypto cryptos are 'aes' and 'xchacha'" if [ "$xkeyfile" != "" ] then mkdir -p /etc/sdm/assets/cryptroot [ ! -f /etc/sdm/assets/cryptroot/$xkeyfile ] && cp $xkeyfile /etc/sdm/assets/cryptroot xkeyfile="$(basename $xkeyfile)" fi rm -f /etc/sdmcryptctl printf "# Runtime configuration for sdm-cryptconfig\n" >/etc/sdmcryptctl printf "mappername:$xmapper\nxcrypto:$xcrypto\nkeyfile:$xkeyfile\nxnopwd:$xnopwd\n" > /etc/sdmcryptctl if [ $xsdm -eq 0 ] then if [ ! -f /usr/local/bin/sdmcryptfs ] then if [ -f $src/sdmcryptfs ] then cryptolog "Copy sdmcryptfs from $src" noconsole cp $src/sdmcryptfs /usr/local/bin else cryptolog "Copy sdmcryptfs from GitHub" noconsole curl --fail --silent --show-error -L https://github.com/gitbls/sdm/raw/master/sdmcryptfs -o /usr/local/bin/sdmcryptfs chmod 755 /usr/local/bin/sdmcryptfs fi fi fi for o in doapt-installs config mkinitramfs updateboot do case "$o" in doapt-installs) [ $xssh -eq 1 ] && db="dropbear-initramfs dropbear-bin" || db="" apps="cryptsetup cryptsetup-initramfs cryptsetup-bin lz4 gdisk e2fsprogs $db" cryptolog "Install $apps" noconsole if [ $xssh -eq 1 ] then cryptolog "" noconsole cryptolog "** Ignore dropbear WARNINGs about authorized_keys file **" noconsole cryptolog " initramfs will be rebuilt with the authorized_keys file later" noconsole cryptolog "" noconsole sleep 5 fi installpkgsif "$apps" ;; config) # Save key values so they can be checked in sdm-cryptfs-cleanup printf "xsdm:$xsdm\nxquiet:$xquiet\nxnoexpand:$xnoexpand\nxnolastrb:$xnolastrb\nxsshbash:$xsshbash\nxdebug:$xdebug\n" >>/etc/sdmcryptctl printf "fstype:$(lsblk -o fstype --noheadings $(findmnt -n -o source /))\n" >>/etc/sdmcryptctl #Debug aid printf "$(systemctl get-default)\n" >>/etc/sdmcryptctl doconfiginitramfs if [ $xwifi -eq 1 ] then if [ $xwifipsk -eq 1 ] then cryptolog "Make WiFi PSK" noconsole pwd=$((IFS='=' read junk psk ; echo "$psk") < <((wpa_passphrase "$xwifissid" "$xwifipwd" | grep $'\tpsk='))) hashed=hashed else pwd="$xwifipwd" hashed="" fi wifimakewpa "$pwd" "$hashed" wificonfiginitramfs fi ;; mkinitramfs) domkinitramfs ;; updateboot) doupdateconfig configcleanupsvc ;; esac done if [ $xsdm -eq 1 ] then # # if started via sdm, clean up # systemctl disable sdm-auto-encrypt > /dev/null 2>&1 rm -f /etc/systemd/system/sdm-auto-encrypt.service fi # # Configure the system so that encryption works # For an as-yet not determined reason quiet in cmdline.txt and plymouth # cause the system to be unbootable bc the cryptroot unlock prompt is hidden # if [ "$(systemctl get-default)" == "graphical.target" ] then # # Desktop. Enable console boot and modify quietness unless --quiet # if [ "$(systemctl get-default)" == "graphical.target" ] then cryptolog "Disable graphical console for encryption process; will be reset to $(systemctl get-default) later" noconsole systemctl -q set-default multi-user.target fi fi if systemctl --quiet is-enabled getty@tty1 then cryptolog "Disable getty@tty1; will be re-enabled later" noconsole systemctl -q disable getty@tty1 echo "re-enable-tty1" >>/etc/sdmcryptctl fi if [ $xquiet -eq 0 ] then cryptolog "Enable verbose system restart" noconsole grep -q -s quiet /boot/firmware/cmdline.txt && echo "clquiet" >>/etc/sdmcryptctl # NB restoring splash currently disabled bc passphrase prompt gets hidden grep -q -s splash /boot/firmware/cmdline.txt && echo "clsplash" >>/etc/sdmcryptctl sed -i "s/ quiet//g" /boot/firmware/cmdline.txt sed -i "s/ splash//g" /boot/firmware/cmdline.txt for svc in plymouth-start plymouth-read-write plymouth-quit-wait # plymouth-reboot plymouth-quit do systemctl mask $svc >/dev/null 2>&1 done fi printinfo if [ $xreboot -eq 1 ] then wait_startup_complete "sdm-cryptoconfig: Wait for system startup to complete" secs=10 logger "sdm-cryptconfig: System will restart in $secs seconds" cryptolog "System will restart in $secs seconds" sleep $secs logger "sdm-cryptconfig: System restarting now" cryptolog "System restarting now" sleep 2 reboot exit 0 else [ $xsdm -eq 1 ] && cryptolog "Complete. Use tty[2-8] if needed" exit 0 fi