#!/bin/sh

# Fripost's postinstall scripts. Should be run after setting up the
# users (06), and ideally before updating the initramfs (10).
#
# Copyright © 2013 Guilhem Moulin <guilhem@fripost.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

# TODO: blacklist firewire-related modules, to defeat DMA-based attacks.

set -ue

. /lib/fripost-partman/base.sh
import=/cdrom/include
seed_urandom

# Update the information below the progress bar. Also, log the argument.
progress() {
    log "$1"
    db_subst base-installer/progress/fripost WHAT "$1"
    db_progress INFO base-installer/progress/fripost
}


#######################################################################
# Ensure OpenSSH is installed, and generate a new key, longer than
# default.

progress "Installing packages"
/bin/apt-install debconf initramfs-tools openssh-server
sshHostKey=/target/etc/ssh/ssh_host_rsa_key
rm -f "${sshHostKey}" "${sshHostKey}.pub"
progress "Generating public/private rsa key pair (OpenSSH)"
/bin/in-target /usr/bin/ssh-keygen -b 4096 -t rsa -N '' \
    -C "${sshHostKey#/target}" -f "${sshHostKey#/target}"


#######################################################################
# Change initramfs defaults

sed -ri -e 's/^#?\s*MODULES=.*/MODULES=dep/' \
        -e 's/^#?\s*COMPRESS=.*/COMPRESS=xz/' \
        /target/etc/initramfs-tools/initramfs.conf

sed -nr '/^\s*(\S+)\s+\S+\s+swap\s.*/ {s//RESUME=\1/p;q}' /target/etc/fstab \
    >> /target/etc/initramfs-tools/conf.d/resume


#######################################################################
# Put dropbear in the initrd if full disk encryption is desired.

# Get username of the first user
db_get passwd/username
user="$RET"

db_get fripost/encrypt
encrypt=$RET
if [ "$encrypt" = true ]; then
    # Put dropbear in the initrd
    progress "Installing dropbear"
    /bin/apt-install dropbear

    cat /var/lib/fripost/initrd-modules >> /target/etc/initramfs-tools/modules

    rm -rf /target/etc/dropbear \
           /target/etc/initramfs-tools/etc/dropbear/dropbear_rsa_host_key

    # The default is not to copy the keys from the OpenSSH server to the
    # initrd, because it's trivial for an attacker with physical access
    # to the box to uncompress it and get hold of the private keys.

    db_get fripost/dropbear-use-openssh-key
    if [ "$RET" = true ]; then
        progress "Converting OpenSSH rsa key to dropbear format"
        /bin/in-target /usr/lib/dropbear/dropbearconvert openssh dropbear \
            ${sshHostKey#/target} \
            /etc/initramfs-tools/etc/dropbear/dropbear_rsa_host_key
    else
        progress "Generating public/private rsa key pair (dropbear)"
        /bin/in-target /usr/bin/dropbearkey -t rsa -s 4096 \
            -f /etc/initramfs-tools/etc/dropbear/dropbear_rsa_host_key
    fi

    progress "Copying authorized_keys to the initrd"
    rm -rf /target/etc/initramfs-tools/root/.ssh
    mkdir -pm0700 /target/etc/initramfs-tools/root/.ssh
    copy_authorized_keys $import/authorized_keys /target/etc/initramfs-tools/root/.ssh/authorized_keys \
                         'no-port-forwarding,no-agent-forwarding,no-X11-forwarding,no-pty,command="/bin/cat >/lib/cryptsetup/passfifo"'

    # Get the [address:]port to make dropbear listen to
    db_get fripost/initrd-ssh-port
    port="${RET:-1024-49151}"
    min=${port%-*}
    max=${port#*-}
    if [ $port = "$min-$max" -a $min -le $max ]; then
        # Pick a random port in the given range
        port=$(/target/usr/bin/od -An -N2 -i /dev/urandom)
        port=$(( $port % ($max + 1 - $min) + $min ))
    fi

    # See dropbear(8) for the list of options.
    log "Changing dropbear's options; port $port"
    echo "PKGOPTION_dropbear_OPTION=\"-sgjk -p $port\"" >>/target/etc/initramfs-tools/initramfs.conf
fi


#######################################################################

progress "Updating OpenSSH's server configuration"
rm -f /target/etc/ssh/ssh_host_dsa_key /target/etc/ssh/ssh_host_dsa_key.pub
cp /var/lib/fripost/sshd_config /target/etc/ssh/sshd_config


#######################################################################
# Remove unnecessary packages

# TODO: check for dummy packages / RCs in a weekly crontab.
dpkg_remove=$(mktemp -p /target/tmp)
cat > "$dpkg_remove" <<- EOF
	acpi
	dictionaries-common
	eject
	gamin
	ispell
	laptop-detect
	nano
	tasksel
	wamerican
	wbritish
EOF
/bin/in-target /usr/bin/xargs -a"${dpkg_remove#/target}" \
    debconf-apt-progress --no-progress -- apt-get -y autoremove --purge
rm -f "$dpkg_remove"


#######################################################################
# Remove /media and remove its related entries from the fstab.
# It's a bit dirty to remove what we created earlier, but /media/cdrom
# is required in the target, because apt gets some packages on that
# pool.

db_get fripost/keep-media-directory
if [ "$RET" = false ]; then
    log "Removing /media and amending the fstab"
    sed -nr 's@^\S+\s+(/target/media/\S+)\s.*@\1@p' /proc/mounts \
      | while read dir; do
            log "Unmounting $dir"
            /bin/umount "$dir"
        done
    sed -ri '/^[^#[:blank:]]+\s+\/media\//d' /target/etc/fstab

    for mp in /target/media/*; do
        if [ -h "$mp" ]; then
            rm -f "$mp"
        elif [ -d "$mp" ]; then
            rmdir "$mp"
        elif [ -e "$mp" ]; then
            fatal "Could not remove $mp"
        fi
    done
    rmdir /target/media
fi


#######################################################################
# Final notice before rebooting

if [ "$encrypt" = false ]; then
    # There is no dropbear
    template=fripost/sshd-fprs-nodropbear_text
else
    template=fripost/sshd-fprs_text
    db_subst "$template" PORT "$port"

    # Convert the key to OpenSSH format, so we can use ssh-keygen
    sshPubKey2=$(mktemp)
    /usr/sbin/chroot /target /usr/bin/dropbearkey -y \
        -f /etc/initramfs-tools/etc/dropbear/dropbear_rsa_host_key \
        | grep -E '^(ssh-(dss|rsa|ed25519)|ecdsa-sha2-nistp(256|384|521))' > "$sshPubKey2"
    db_subst "$template" SSHFPR_INITRD "$(sshfprs $sshPubKey2)"
    rm -f "$sshPubKey2"
fi
db_subst "$template" USER              "$user"
db_subst "$template" IPv4              "$(getIPv4)"
db_subst "$template" SSHFPR_SERVER     "$(sshfprs ${sshHostKey}.pub)"
db_subst "$template" SSHFPR_AUTHORIZED "$(sshfprs $import/authorized_keys '    - ')"

db_get fripost/final-notice
if [ "$RET" = true ]; then
    # Start the SSH daemon to let the user's client to recognize the server
    # hence make the weak TOFU model MiTM-immune.
    progress "Starting OpenSSH"
    /usr/sbin/chroot /target /usr/sbin/service ssh start

    db_settitle fripost/sshd-fprs_title
    db_input critical "$template"
    db_go

    # Don't show the usual "reboot in progress" notice
    db_set finish-install/reboot_in_progress ''
    db_fset finish-install/reboot_in_progress seen true

    progress "Stopping OpenSSH"
    /usr/sbin/chroot /target /usr/sbin/service ssh stop
fi


#######################################################################
# Allow the user to log in via SSH at the next login.

progress "Fixing permissions on home directories"
db_get adduser/homedir-permission || true
# XXX: Workaround for #398802
if [ "${RET:-true}" = false ]; then
    # Fix permissions for existing users
    . /target/etc/adduser.conf
    sed -rn "s@^([^:]+:){2}([0-9]+):([^:]*:){2}(/[^:]*):.*@\2 \4@p" /target/etc/passwd \
    | while read uuid home; do
        [ $uuid -ge $FIRST_UID -a $uuid -le $LAST_UID -a -d /target"$home" ] || continue
        log "Fixing permissions on $home"
        chmod 0700 /target"$home"
    done

    # Fix permissions for future users
    sed -ri 's/^(DIR_MODE)=[0-9]+/\1=0700/' /target/etc/adduser.conf
fi

ugid="$(sed -rn "s@^$user:[^:]*:([0-9]+:[0-9]+):.*@\1@p" /target/etc/passwd)"
home="$(sed -rn "s@^$user:([^:]*:){4}(/[^:]*):.*@\2@p"   /target/etc/passwd)"

# Create ~/.ssh/authorized_keys and fix ownership. We create it *after*
# stopping the SSH daemon to ensure that users can verify the
# fingerprint but cannot log in.
progress "Copying authorized_keys to ~$user/.ssh"
[ -d /target"$home/.ssh" ] || mkdir -m0700 /target"$home/.ssh"
copy_authorized_keys $import/authorized_keys /target"$home/.ssh/authorized_keys"
chown -R "$ugid" /target"$home/.ssh" # Probably 1000:1000, but who knows

# Enable ssh login for "$user"
/bin/in-target /usr/sbin/addgroup --system ssh-login
/bin/in-target /usr/sbin/adduser  "$user"  ssh-login