#!/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 # # 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 . # 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}" ####################################################################### # 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. Failure to read a keyfile # makes dropbear disable the corresponding algorithm (including # key-based authentication), in our case DSS/DSA. # XXX This is a dirty fix for bug #614981 log "Changing dropbear's options; port $port" sed -i "s@^\s*/sbin/dropbear\$@& -d '' -sgjk -p $port@" \ /target/usr/share/initramfs-tools/scripts/init-premount/dropbear # Sadly /usr/lib/finish-install.d/10update-initramfs only updates # the ramdisk if both cryptsetup *and* console-setup are installed. # (Cf. #694156 and #696773.) So we perform the update manually here. progress "Generating new initramfs image" /bin/in-target /usr/sbin/update-initramfs -u -t 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 ####################################################################### # Install and activate SELinux # TODO: would be better to have our own policy instead of amending the # default one. db_get fripost/activate-selinux if [ "$RET" = true ]; then progress "Installing SELinux" # Recommended packages include graphical tools... /bin/in-target /usr/bin/debconf-apt-progress --no-progress -- \ apt-get -y install --no-install-recommends \ selinux-basics selinux-policy-default selinux-policy-dev auditd progress "Activating SELinux" /bin/in-target /usr/sbin/selinux-activate sed -ri 's/^#?\s*(FSCKFIX)=(yes|no)\s*(\s#.*)?$/\1=yes/' \ /target/etc/default/rcS progress "Running update-grub" grep -q '^GRUB_CMDLINE_LINUX=' /target/etc/default/grub \ || fatal "Missing definition of 'GRUB_CMDLINE_LINUX' in /etc/default/grub" GRUB_CMDLINE="console=tty0 security=selinux enforcing=1" # ^ TODO: we should leave (non SELinux-related) existing # configuration options sed -ri "s/^(GRUB_CMDLINE_LINUX)=.*/\1=\"$GRUB_CMDLINE\"/" \ /target/etc/default/grub /bin/in-target /usr/sbin/update-grub if /bin/in-target /bin/sh -c "dpkg-query -s postfix >/dev/null 2>&1"; then progress "Running postfix-nochroot" echo 'SYNC_CHROOT=n' >> /target/etc/default/postfix /bin/in-target /usr/sbin/postfix-nochroot fi # TODO: in a crontab: check-selinux-installation fi ####################################################################### # 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 ispell laptop-detect nano tasksel wamerican wbritish EOF # XXX: the dummy package 'module-init-tools' is a dependency for 'acpid'. #/usr/sbin/chroot /target /usr/bin/dpkg-query \ # --show --showformat='${binary:Package} ${binary:Summary}\n' \ # | sed -rn 's/^(\S+)\s.*\btransitional dummy package\b.*/\1/p' \ # >> "$dpkg_remove" /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 sshHostKey2=$(mktemp) /usr/sbin/chroot /target /usr/bin/dropbearkey -y \ -f /etc/initramfs-tools/etc/dropbear/dropbear_rsa_host_key \ | grep -E '^(ssh-(dss|rsa)|ecdsa-sha2-nistp(256|384|521))' > "$sshHostKey2" db_subst "$template" SSHFPR_INITRD "$(/usr/bin/ssh-keygen -lf $sshHostKey2)" rm -f "$sshHostKey2" fi db_subst "$template" USER "$user" db_subst "$template" IPv4 "$(getIPv4)" db_subst "$template" SSHFPR_SERVER "$(/usr/bin/ssh-keygen -lf $sshHostKey)" 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