From c4e4112bdc8aa5fe92d797ab77744d3bcd70caf9 Mon Sep 17 00:00:00 2001 From: Eric Hameleers Date: Fri, 22 Jan 2016 15:15:17 +0100 Subject: Add support for a LUKS-encrypted /home in the USB Live version. Using iso2usb.sh script's new '-c' parameter, you can define the size for a container file in the root of the USB stick's Linux partition. - The container file will be loop-mounted and LUKS-encrypted and the Live OS will mount the filesystem inside the container on /home/. - The LUKS passphrase will be defined when executing the 'iso2usb.sh' script. - The original /home content of the ISO will be copied into the LUKS-encrypted container during execution of the 'iso2usb.sh' script. - If for whatever reason you do not want to unlock & mount the LUKS container during boot, you must add the boot parameter " luksvol= " to the syslinux or grub commandline. --- iso2usb.sh | 205 +++++++++++++++++++++++++++++++++++++++++-------- liveinit | 56 ++++++++++++++ make_slackware_live.sh | 9 ++- 3 files changed, 234 insertions(+), 36 deletions(-) diff --git a/iso2usb.sh b/iso2usb.sh index 680fc29..e9c27dd 100644 --- a/iso2usb.sh +++ b/iso2usb.sh @@ -39,10 +39,17 @@ VERBOSE=0 # Seconds to add to the initrd as wait-for-root value: WAIT=5 +# No LUKS encryption by default: +DOLUKS=0 +CNTDEV="" +CNTFILE="" +LODEV="" + # Define ahead of time, so that cleanup knows about them: IMGDIR="" EFIMNT="" ISOMNT="" +LKSMNT="" USBMNT="" # @@ -56,8 +63,16 @@ cleanup() { # During cleanup, do not abort due to non-zero exit code: set +e sync + if [ $DOLUKS -eq 1 ]; then + if mount |grep -q ${CNTDEV} ; then + umount -f ${CNTDEV} + cryptsetup luksClose ${CNTBASE} + losetup -d ${LODEV} + fi + fi [ -n "${EFIMNT}" ] && ( /sbin/umount -f ${EFIMNT} 2>/dev/null; rmdir $EFIMNT ) [ -n "${ISOMNT}" ] && ( /sbin/umount -f ${ISOMNT} 2>/dev/null; rmdir $ISOMNT ) + [ -n "${LKSMNT}" ] && ( /sbin/umount -f ${LKSMNT} 2>/dev/null; rmdir $LKSMNT ) [ -n "${USBMNT}" ] && ( /sbin/umount -f ${USBMNT} 2>/dev/null; rmdir $USBMNT ) [ -n "${IMGDIR}" ] && ( rm -rf $IMGDIR ) set -e @@ -75,30 +90,38 @@ cat < Full path to the ISO image file -# -o|--outdev The device name of your USB drive -# -p|--persistence Custom name of the 'persistence' directory -# -u|--unattended Do not ask any questions -# -v|--verbose Show verbose messages -# -w|--wait Pause boot seconds to initialize USB +# -c|--crypt size|perc Add LUKS encrypted /home ; parameter is the +# requested size of the container in kB, MB, GB, +# or as a percentage of free space. +# Examples: '-c 125M', '-c 1.3G', '-c 20%'. +# -f|--force Ignore most warnings (except the back-out). +# -h|--help This help. +# -i|--infile Full path to the ISO image file. +# -o|--outdev The device name of your USB drive. +# -p|--persistence Custom name of the 'persistence' directory. +# -u|--unattended Do not ask any questions. +# -v|--verbose Show verbose messages. +# -w|--wait Add seconds wait time to initialize USB. # -# Example: +# Examples: # # $(basename $0) -i ~/download/slackware64-live-14.2.iso -o /dev/sdX +# $(basename $0) -i slackware64-live-xfce-current.iso -o /dev/sdX -c 750M -w 15 # EOT } # Add longer USB WAIT to the initrd: update_initrd() { - # USB boot medium needs a few seconds boot delay else the overlay will fail. + IMGFILE="$1" + # USB boot medium needs a few seconds boot delay else the overlay will fail. # Check if we need to update the wait-for-root file in the initrd: - OLDWAIT=$(gunzip -cd ${USBMNT}/boot/initrd.img |cpio -i --to-stdout wait-for-root 2>/dev/null) - [ "$OLDWAIT" = "$WAIT" ] && return + OLDWAIT=$(gunzip -cd ${IMGFILE} |cpio -i --to-stdout wait-for-root 2>/dev/null) + if [ "$OLDWAIT" = "$WAIT" -a $DOLUKS -eq 0 ]; then + return + fi if [ -z "$IMGDIR" ]; then # Create a temporary extraction directory for the initrd: @@ -113,17 +136,120 @@ update_initrd() { echo "--- Extracting Slackware initrd and adding rootdelay for USB..." cd ${IMGDIR} - gunzip -cd ${USBMNT}/boot/initrd.img \ + gunzip -cd ${IMGFILE} \ | cpio -i -d -H newc --no-absolute-filenames echo "--- Updating 'waitforroot' time from '$OLDWAIT' to '$WAIT':" echo ${WAIT} > wait-for-root + + if [ $DOLUKS -eq 1 ]; then + if ! grep -q ${CNTFILE} luksdev ; then + echo "--- Adding '${CNTFILE}' as LUKS /home:" + echo "${CNTFILE}" >> luksdev + fi + fi + echo "--- Compressing the initrd image again:" chmod 0755 ${IMGDIR} - find . |cpio -o -H newc |gzip > ${USBMNT}/boot/initrd.img + find . |cpio -o -H newc |gzip > ${IMGFILE} cd - 2>/dev/null rm -rf $IMGDIR/* } # End of update_initrd() +# Create a container file in the empty space of the partition +create_container() { + CNTPART=$1 + CNTSIZE=$2 + CNTBASE=$3 + + # Determine size of the target partition (in MB), and the free space: + PARTSIZE=$(df -P -BM ${CNTPART} |tail -1 |tr -s '\t' ' ' |cut -d' ' -f2) + PARTSIZE=${PARTSIZE%M} + PARTFREE=$(df -P -BM ${CNTPART} |tail -1 |tr -s '\t' ' ' |cut -d' ' -f4) + PARTFREE=${PARTFREE%M} + + if [ $PARTFREE -lt 10 ]; then + echo "** Free space on USB partition is less than 10 MB;" + echo "** Not creating a container file!" + exit 1 + fi + + # Determine requested container size (allow for '%|k|K|m|M|g|G' suffix): + case "${CNTSIZE: -1}" in + "%") CNTSIZE="$(( $PARTFREE * ${CNTSIZE%\%} / 100 ))" ;; + "k") CNTSIZE="$(( ${CNTSIZE%k} / 1024 ))" ;; + "K") CNTSIZE="$(( ${CNTSIZE%K} / 1024 ))" ;; + "m") CNTSIZE="${CNTSIZE%m}" ;; + "M") CNTSIZE="${CNTSIZE%M}" ;; + "g") CNTSIZE="$(( ${CNTSIZE%g} * 1024 ))" ;; + "G") CNTSIZE="$(( ${CNTSIZE%G} * 1024 ))" ;; + *) ;; + esac + + if [ $CNTSIZE -le 0 ]; then + echo "** Container size must be larger than ZERO!" + echo "** Check your '-c' commandline parameter." + exit 1 + elif [ $CNTSIZE -ge $PARTFREE ]; then + echo "** Not enough free space for container file!" + echo "** Check your '-c' commandline parameter." + exit 1 + fi + + # Create an empty container file (allow for previously created ones): + for III in $(seq 1 9); do + if [ ! -f $USBMNT/${CNTBASE}0${III} ]; then + break + fi + done + if [ $III -eq 9 ]; then + echo "*** You already have NINE container files? Please clean up first." + exit 1 + else + echo "--- Creating ${CNTSIZE}MB container file using 'dd if=/dev/urandom', patience please..." + dd if=/dev/urandom of=$USBMNT/${CNTBASE}0${III}.img bs=1M count=$CNTSIZE + CNTFILE="${CNTBASE}0${III}.img" + fi + + # Setup a loopback device that we can use with cryptsetup: + LODEV=$(losetup -f) + losetup $LODEV $USBMNT/${CNTBASE}0${III}.img + if [ $DOLUKS -eq 1 ]; then + # Format the loop device with LUKS: + echo "--- Encrypting the container file with LUKS; enter 'YES' and a passphrase..." + cryptsetup -y luksFormat $LODEV + # Unlock the LUKS encrypted container: + echo "--- Unlocking the LUKS container requires your passphrase again..." + cryptsetup luksOpen $LODEV ${CNTBASE} + CNTDEV=/dev/mapper/${CNTBASE} + else + CNTDEV=$LODEV + fi + # Format the now available block device with a linux fs: + mkfs.ext4 ${CNTDEV} + # Tune the ext4 filesystem: + tune2fs -m 0 -c 0 -i 0 ${CNTDEV} + # Create a mount point for the unlocked container: + LKSMNT=$(mktemp -d -p /mnt -t alienlks.XXXXXX) + if [ ! -d $LKSMNT ]; then + echo "*** Failed to create a temporary mount point for the LUKS container!" + exit 1 + else + chmod 711 $LKSMNT + fi + # Copy the original /home content into the container: + echo "--- Copying /home from LiveOS to LUKS container..." + HOMESRC=$(find ${USBMNT} -name "0099-slackware_zzzconf*" |tail -1) + mount ${CNTDEV} ${LKSMNT} + unsquashfs -n -d ${LKSMNT}/temp ${HOMESRC} /home + mv ${LKSMNT}/temp/home/* ${LKSMNT}/ + rm -rf ${LKSMNT}/temp + # And clean up after ourselves: + umount ${CNTDEV} + cryptsetup luksClose ${CNTBASE} + losetup -d ${LODEV} + +} # End of create_container() { + # # -- end of function definitions -- # @@ -135,6 +261,11 @@ if [ -z "$1" ]; then fi while [ ! -z "$1" ]; do case $1 in + -c|--crypt) + LUKSSIZE="$2" + DOLUKS=1 + shift 2 + ;; -f|--force) FORCE=1 shift @@ -203,7 +334,7 @@ fi # Are all the required not-so-common add-on tools present? PROG_MISSING="" -for PROGN in blkid cpio extlinux fdisk gdisk iso-info mkdosfs sgdisk ; do +for PROGN in blkid cpio extlinux fdisk gdisk iso-info mkdosfs sgdisk unsquashfs ; do if ! PATH="/sbin:$PATH" which $PROGN 1>/dev/null 2>/dev/null ; then PROG_MISSING="${PROG_MISSING}-- $PROGN\n" fi @@ -310,27 +441,12 @@ else chmod 711 $USBMNT fi -# Loop-mount the ISO (or 1st partition if this is a hybrid ISO): -/sbin/mount -o loop ${SLISO} ${ISOMNT} - -if [ $EFIBOOT -eq 1 ]; then - # Mount the EFI partition and copy /EFI as well as /boot directories into it: - /sbin/mount -t vfat -o shortname=mixed ${TARGET}2 ${USBMNT} - mkdir -p ${USBMNT}/EFI/BOOT - rsync -rlptD ${ISOMNT}/EFI/BOOT/* ${USBMNT}/EFI/BOOT/ - mkdir -p ${USBMNT}/boot - rsync -rlptD ${ISOMNT}/boot/* ${USBMNT}/boot/ - # Add more USB WAIT seconds to the initrd: - update_initrd ${USBMNT}/boot/initrd.img -fi - -# No longer needed: -/sbin/umount ${USBMNT} -/sbin/umount ${EFIMNT} - # Mount the Linux partition: /sbin/mount -t auto ${TARGET}3 ${USBMNT} +# Loop-mount the ISO (or 1st partition if this is a hybrid ISO): +/sbin/mount -o loop ${SLISO} ${ISOMNT} + # Copy the ISO content into the USB Linux partition: echo "--- Copying files from ISO to USB... takes some time." rsync -a ${RVERBOSE} --exclude=EFI ${ISOMNT}/* ${USBMNT}/ @@ -341,6 +457,11 @@ if [ -n "$VERSION" ]; then echo "$VERSION" > ${USBMNT}/.isoversion fi +if [ $DOLUKS -eq 1 ]; then + # Create LUKS container file: + create_container ${TARGET}3 ${LUKSSIZE} slhome +fi + # Add more USB WAIT seconds to the initrd: update_initrd ${USBMNT}/boot/initrd.img @@ -354,6 +475,24 @@ mv ${USBMNT}/boot/extlinux/isolinux.cfg ${USBMNT}/boot/extlinux/extlinux.conf rm ${USBMNT}/boot/extlinux/isolinux.* /sbin/extlinux --install ${USBMNT}/boot/extlinux +# No longer needed: +/sbin/umount ${USBMNT} + +if [ $EFIBOOT -eq 1 ]; then + # Mount the EFI partition and copy /EFI as well as /boot directories into it: + /sbin/mount -t vfat -o shortname=mixed ${TARGET}2 ${USBMNT} + mkdir -p ${USBMNT}/EFI/BOOT + rsync -rlptD ${ISOMNT}/EFI/BOOT/* ${USBMNT}/EFI/BOOT/ + mkdir -p ${USBMNT}/boot + rsync -rlptD ${ISOMNT}/boot/* ${USBMNT}/boot/ + # Add more USB WAIT seconds to the initrd: + update_initrd ${USBMNT}/boot/initrd.img +fi + +# No longer needed: +/sbin/umount ${USBMNT} +/sbin/umount ${EFIMNT} + # Unmount/remove stuff: cleanup diff --git a/liveinit b/liveinit index 6912d16..935495a 100755 --- a/liveinit +++ b/liveinit @@ -50,6 +50,7 @@ DEBUG=0 INITRD=$(cat /initrd-name) WAIT=$(cat /wait-for-root) KEYMAP=$(cat /keymap) +LUKSVOL=$(cat /luksdev) INIT=/sbin/init PATH="/sbin:/bin:/usr/sbin:/usr/bin" @@ -100,6 +101,10 @@ for ARG in $(cat /proc/cmdline); do locale=*) LOCALE=$(echo $ARG | cut -f2 -d=) ;; + luksvol=*) + # Format: luksvol=file1[:/mountpoint1][,file1[:/mountpoint2],...] + LUKSVOL=$(echo $ARG | cut -f2 -d=) + ;; noload=*) NOLOAD=$(echo $ARG | cut -f2 -d=) ;; @@ -482,6 +487,57 @@ EOPW # Copy contents of rootcopy directory (may be empty) to overlay: cp -af /mnt/media/${LIVEMAIN}/rootcopy/* /mnt/overlay/ 2>/dev/null + # Bind any LUKS container into the Live filesystem: + if [ ! -z "$LUKSVOL" ]; then + # Even without persistence, we need to be able to write to the partition: + mount -o remount,rw /mnt/media + for luksvol in $(echo $LUKSVOL |tr ',' ' '); do + luksfil="$(echo $luksvol |cut -d: -f1)" + luksmnt="$(echo $luksvol |cut -d: -f2)" + luksnam="$(echo $(basename $luksfil) |tr '.' '_')" + if [ "$luksmnt" = "$luksfil" ]; then + # No optional mount point specified, so we use the default: /home/ + luksmnt="/home" + fi + + # The losetup of busybox is different from the real losetup - watch out! + lodev=$(losetup -f) + if [ -z "$lodev" ]; then + # We exhausted the available loop devices, so create the block device: + for NOD in $(seq 0 64); do + if [ ! -b /dev/loop${NOD} ]; then + mknod -m660 /dev/loop${NOD} b 7 ${NOD} + break + fi + done + lodev=/dev/loop${NOD} + elif [ ! -b $lodev ]; then + # We exhausted the available loop devices, so create the block device: + mknod -m660 $lodev b 7 $(echo $lodev |sed %/dev/loop%%) + fi + losetup $lodev /mnt/media/$luksfil + echo "Unlocking LUKS encrypted container '$luksfil' at mount point '$luksmnt'" + cryptsetup luksOpen $lodev $luksnam /dev/tty0 2>&1 + if [ $? -ne 0 ]; then + echo "${INITRD}: Failed to unlock LUKS container '$luksfil'... trouble ahead." + fi + + # Create the directory if it does not exist (unlikely): + mkdir -p /mnt/overlay/$luksmnt + + # Let Slackware mount the unlocked container: + luksfs=$(blkid /dev/mapper/$luksnam |rev |cut -d'"' -f2 |rev) + if ! grep -q /dev/mapper/$luksnam /mnt/overlay/etc/fstab ; then + echo "/dev/mapper/$luksnam $luksmnt $luksfs defaults 1 1" >> /mnt/overlay/etc/fstab + fi + # On shutdown, ensure that the container gets locked again: + if ! grep -q "$luksnam $luksmnt" /mnt/overlay/etc/crypttab ; then + echo "$luksnam $luksmnt" >> /mnt/overlay/etc/crypttab + fi + + done + fi + # --------------------------------------------------------------------- # # SLACKWARE LIVE - !END! # # --------------------------------------------------------------------- # diff --git a/make_slackware_live.sh b/make_slackware_live.sh index c83623d..0f7a577 100755 --- a/make_slackware_live.sh +++ b/make_slackware_live.sh @@ -31,6 +31,7 @@ # - uses overlayfs to bind multiple squashfs modules together # - you can add your own modules into ./addons/ or ./optional subdirectories. # - persistence is enabled when writing the ISO to USB stick using iso2usb.sh. +# - LUKS encrypted homedirectory is optional on USB stick using iso2usb.sh. # # ----------------------------------------------------------------------------- @@ -155,8 +156,9 @@ SEQ_MSB="tagfile:a,ap,d,e,f,k,l,n,t,tcl,x,xap,xfce,y pkglist:slackextra,mate loc # - each will become a squashfs module: SEQ_CIN="tagfile:a,ap,d,e,f,k,l,n,t,tcl,x,xap,xfce,y pkglist:slackextra,cinnamon local:slackpkg+" -# List of kernel modules required for a live medium to boot properly: -KMODS=${KMODS:-"squashfs:overlay:loop:xhci-pci:ehci-pci:uhci_hcd:usb-storage:hid:usbhid:hid_generic:jbd:mbcache:ext3:ext4:isofs:fat:nls_cp437:nls_iso8859-1:msdos:vfat"} +# List of kernel modules required for a live medium to boot properly; +# Lots of HID modules added to support keyboard input for LUKS password entry: +KMODS=${KMODS:-"squashfs:overlay:loop:xhci-pci:ohci-pci:ehci-pci:xhci-hcd:uhci-hcd:ehci-hcd:usb-storage:hid:usbhid:hid-generic:hid-cherry:hid-logitech:hid-logitech-dj:hid-logitech-hidpp:hid-lenovo:hid-microsoft:jbd:mbcache:ext3:ext4:isofs:fat:nls_cp437:nls_iso8859-1:msdos:vfat"} # What compression to use for the squashfs modules? # Default is xz, alternatives are gzip, lzma, lzo: @@ -1330,13 +1332,14 @@ KVER=$(ls --indicator-style=none ${LIVE_ROOTDIR}/lib/modules/ |head -1) # Create an initrd for the generic kernel, using a modified init script: echo "-- Creating initrd for kernel-generic $KVER ..." -chroot ${LIVE_ROOTDIR} /sbin/mkinitrd -c -w ${WAIT} -l us -o /boot/initrd_${KVER}.gz -k ${KVER} -m ${KMODS} 1>${DBGOUT} 2>${DBGOUT} +chroot ${LIVE_ROOTDIR} /sbin/mkinitrd -c -w ${WAIT} -l us -o /boot/initrd_${KVER}.gz -k ${KVER} -m ${KMODS} -L -C dummy 1>${DBGOUT} 2>${DBGOUT} cat $LIVE_TOOLDIR/liveinit | sed \ -e "s/@LIVEMAIN@/$LIVEMAIN/g" \ -e "s/@MEDIALABEL@/$MEDIALABEL/g" \ -e "s/@PERSISTENCE@/$PERSISTENCE/g" \ -e "s/@DARKSTAR@/$LIVE_HOSTNAME/g" \ > ${LIVE_ROOTDIR}/boot/initrd-tree/init +cat /dev/null > ${LIVE_ROOTDIR}/boot/initrd-tree/luksdev chroot ${LIVE_ROOTDIR} /sbin/mkinitrd 1>/dev/null 2>${DBGOUT} rm -rf ${LIVE_ROOTDIR}/boot/initrd-tree -- cgit v1.2.3