#!/bin/sh

# Copyright 2019 Johannes 'josch' Schauer <josch@debian.org>
# Copyright 2021 Guilhem Moulin <guilhem@debian.org>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.

PREREQ=""

prereqs() {
    echo "$PREREQ"
}

case "$1" in
    prereqs)
        prereqs
        exit 0
    ;;
esac

. /scripts/functions
set -eux

# drives available to the setup system
TARGET_DRIVE="/dev/vda"
CHROOT_TARBALL="/dev/vdb"

# we'll halt execution and hang until the timeout is reached (can't do better)
trap "panic \"couldn't prepare testbed\"" EXIT

# format the target disk with three partitions
GUID_TYPE_BIOS_boot="21686148-6449-6E6F-744E-656564454649" # BIOS boot partition
GUID_TYPE_Linux_FS="0FC63DAF-8483-4772-8E79-3D69D8477DE4"  # Linux filesystem data
GUID_TYPE_LUKS="CA7D7CCB-63ED-4C53-861C-1742536059CC"      # LUKS partition
sfdisk "$TARGET_DRIVE" <<-EOF
	label: gpt
	unit: sectors

	${TARGET_DRIVE}1 : start=$((1024*2)), size=$((1024*2)), type=${GUID_TYPE_BIOS_boot}
	${TARGET_DRIVE}2 : start=$(((1+1)*1024*2)), size=$((512*1024*2)), type=${GUID_TYPE_Linux_FS}
	${TARGET_DRIVE}3 : start=$(((1+1+512)*1024*2)), size=$((16*1024*2))
	${TARGET_DRIVE}4 : start=$(((1+1+512+16)*1024*2)), type=${GUID_TYPE_LUKS}
EOF

BOOT_DEV="${TARGET_DRIVE}2"
CRYPTSWAP_DEV="${TARGET_DRIVE}3"
CRYPTROOT_DEV="${TARGET_DRIVE}4"
CRYPTSWAP_DMNAME="swap_crypt"
CRYPTROOT_DMNAME="root_crypt"
HOSTNAME="debian"

# initialize a new LUKS partition and open it
cryptsetup luksFormat --batch-mode \
    --key-file=/cryptroot/rootfs.key \
    --type=luks2 \
    --pbkdf=argon2id \
    --pbkdf-force-iterations=4 \
    --pbkdf-memory=32 \
    -- "$CRYPTROOT_DEV"
cryptsetup luksOpen --key-file=/cryptroot/rootfs.key --allow-discards \
    -- "$CRYPTROOT_DEV" "$CRYPTROOT_DMNAME"

# create ext2 resp. ext4 file system for /boot resp. the root FS
mke2fs -t ext2 -m0 "$BOOT_DEV"
mke2fs -t ext4 "/dev/mapper/$CRYPTROOT_DMNAME"

# extract the chroot tarball into the target's root FS (excluding /boot/* and special files)
mount -t ext4 "/dev/mapper/$CRYPTROOT_DMNAME" /root
tar -C /root -xf- --xattrs --xattrs-include="*" \
    --exclude="./lost+found" \
    --exclude="./boot/*" \
    --exclude="./dev/*" \
    --exclude="./proc/*" \
    --exclude="./run/*" \
    --exclude="./sys/*" \
    --exclude="./tmp/*" \
    <"$CHROOT_TARBALL"

# extract boot from the chroot tarball into the target's /boot partition
mount -t ext2 "$BOOT_DEV" /root/boot
tar -C /root -xf- --xattrs --xattrs-include="*" "./boot/" <"$CHROOT_TARBALL"


# setup fstab(5) and crypttab(5)
cat >/root/etc/fstab <<-EOF
	/dev/mapper/$CRYPTROOT_DMNAME /    auto errors=remount-ro 0 1
	/dev/mapper/$CRYPTSWAP_DMNAME none swap sw                0 0
	UUID=$(blkid -s UUID -o value "$BOOT_DEV") /boot auto defaults 0 2
EOF
cat >/root/etc/crypttab <<-EOF
	$CRYPTROOT_DMNAME UUID=$(blkid -s UUID -o value "$CRYPTROOT_DEV") none luks,discard
	$CRYPTSWAP_DMNAME $CRYPTSWAP_DEV /dev/urandom cipher=aes-xts-plain64,size=256,discard,swap
EOF

# setup the network
IFACE="eth0" # we can rely on that name since we set net.ifnames=0
cat >/root/etc/network/interfaces <<-EOF
	auto lo
	iface lo inet loopback

	auto $IFACE
	iface $IFACE inet static
	    address 10.0.2.129/24
EOF
echo "$HOSTNAME" >/root/etc/hostname
echo "127.0.0.1 localhost $HOSTNAME" >/root/etc/hosts

# instead of supplying the ip parameter to the kernel cmdline, we tell dropbear
# about it to test this functionality; we use a dedicated IP at initramfs stage
# to check that the network is re-configured as intended after pivoting
echo "IP=\"10.0.2.130:::255.255.255.0::$IFACE:off\"" >/root/etc/initramfs-tools/conf.d/dropbear

# start dropbear on a non-default port to also test this functionality
echo "DROPBEAR_OPTIONS=\"-p 2222\"" >>/root/etc/dropbear/initramfs/dropbear.conf

# copy dropbear's authorized_keys file to ~root/.ssh so we can login to the system's
# SSHd once it finished booting
mkdir -pm0700 /root/root/.ssh
cp -T /root/etc/dropbear/initramfs/authorized_keys /root/root/.ssh/authorized_keys

# add some restrictions to dropbear's authorized_keys file
sed -ri '/^\s*(#|$)/b; s#^#no-port-forwarding,no-agent-forwarding,no-X11-forwarding,command="/bin/cryptroot-unlock" #' \
        /root/etc/dropbear/initramfs/authorized_keys

# mount pseudo- and temporary filesystems so we can chroot in the target system
mount -t devtmpfs none /root/dev
mount -t devpts none /root/dev/pts
mount -t proc none /root/proc
mount -t tmpfs none /root/run
mount -t sysfs none /root/sys

# update the initramfs image
echo RESUME=none >/root/etc/initramfs-tools/conf.d/resume
chroot /root update-initramfs -u


# configure and install GRUB
cat >/root/etc/default/grub <<-EOF
	GRUB_DEFAULT=0
	GRUB_TIMEOUT=0
	GRUB_CMDLINE_LINUX_DEFAULT=""
	GRUB_CMDLINE_LINUX="net.ifnames=0 console=ttyS0"
	GRUB_DISABLE_RECOVERY=true
EOF
chroot /root grub-install --no-floppy --modules=part_gpt "$TARGET_DRIVE"
chroot /root update-grub


# umount everything
for d in /boot /dev/pts /dev /proc /run /sys ""; do
    umount "/root$d"
done
cryptsetup luksClose -- "$CRYPTROOT_DMNAME"

# we're done!  power the setup system down so we can reboot into the
# target system
poweroff -f
