aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile43
-rw-r--r--include/.gitignore (renamed from .gitignore)0
-rwxr-xr-xinclude/partition.sh (renamed from partition.sh)0
-rw-r--r--preseed.cfg57
-rwxr-xr-xpreseed.sh93
-rw-r--r--src/.gitignore3
-rw-r--r--src/fripost-partman-udeb/Makefile13
-rw-r--r--src/fripost-partman-udeb/base.sh527
-rw-r--r--src/fripost-partman-udeb/debian/changelog5
-rw-r--r--src/fripost-partman-udeb/debian/compat1
-rw-r--r--src/fripost-partman-udeb/debian/control21
-rw-r--r--src/fripost-partman-udeb/debian/copyright7
-rw-r--r--src/fripost-partman-udeb/debian/install1
-rwxr-xr-xsrc/fripost-partman-udeb/debian/postinst25
-rwxr-xr-xsrc/fripost-partman-udeb/debian/rules3
-rw-r--r--src/fripost-partman-udeb/debian/templates84
-rw-r--r--src/fripost-partman-udeb/lib/stdbuf.c11
-rw-r--r--src/fripost-postinst-udeb/debian/changelog5
-rw-r--r--src/fripost-postinst-udeb/debian/compat1
-rw-r--r--src/fripost-postinst-udeb/debian/control11
-rw-r--r--src/fripost-postinst-udeb/debian/copyright7
-rw-r--r--src/fripost-postinst-udeb/debian/install2
-rwxr-xr-xsrc/fripost-postinst-udeb/debian/rules3
-rw-r--r--src/fripost-postinst-udeb/debian/templates93
-rwxr-xr-xsrc/fripost-postinst-udeb/finish-install.d/07fripost275
-rw-r--r--src/fripost-postinst-udeb/sshd_config40
-rwxr-xr-xsrc/getname.sh28
-rwxr-xr-xvirtualenv/virt133
28 files changed, 1492 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..93d0c3f
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,43 @@
+ARCH ?= $(shell uname -m | sed -e 's/^x86_64$$/amd64/' -e 's/^i686$$/i386/')
+VERSION = 7.2.0
+
+ISOIMG = debian-${VERSION}-${ARCH}-netinst.iso
+PRESEEDED = $(patsubst %.iso,%-preseeded.iso, ${ISOIMG})
+UDEBS = $(shell ./src/getname.sh)
+CHECKSUMS = MD5 SHA1 SHA256 SHA512
+
+# Preseed
+iso-preseed:
+ make dist/${ARCH}/${PRESEEDED}
+dist/${ARCH}/${PRESEEDED}: preseed.cfg $(wildcard ./include/*) dist/${ARCH}/${ISOIMG} ${UDEBS}
+ ./preseed.sh $@ dist/${ARCH}/${ISOIMG} ${UDEBS}
+
+# Get, verify
+iso-get: dist/${ARCH}/${ISOIMG}
+iso-checksum: $(patsubst %,iso-checksum-%, ${CHECKSUMS})
+
+# Verify a single digest
+iso-checksum-%: dist/${ARCH}/${ISOIMG} dist/${ARCH}/%SUMS dist/${ARCH}/%SUMS.sign
+ @echo Checking $* sum
+ @cd dist/${ARCH}; grep "\s${ISOIMG}$$" $*SUMS | $$(echo $* | sed 's@.*@/usr/bin/\L&sum@') --strict -c
+ gpg --verify dist/${ARCH}/$*SUMS.sign
+
+# Download
+.PRECIOUS: dist/${ARCH}/%
+dist/${ARCH}/%:
+ @[ -d dist/${ARCH} ] || mkdir -p dist/${ARCH}
+ wget -nc -P dist/${ARCH} http://cdimage.debian.org/debian-cd/current/${ARCH}/iso-cd/$*
+
+# All udebs
+udebs: ${UDEBS}
+
+# Single udeb; TODO: GPG sign
+%.udeb: UDEB = $(shell ./src/getname.sh $*)
+%.udeb: $(shell /usr/bin/git ls-files -- src/${UDEB})
+ @cd src/${UDEB} && /usr/bin/debuild -i -us -uc -b -a${ARCH}
+
+clean:
+ @for d in src/*-udeb/; do rm -fv $${d%-udeb/}_*.build $${d%-udeb/}_*.changes $${d%-udeb/}_*.udeb; cd $$d && dh_clean && cd -; done
+ @rm -fv $(patsubst %,dist/${ARCH}/%SUMS, ${CHECKSUMS}) $(patsubst %,dist/${ARCH}/%SUMS.sign, ${CHECKSUMS})
+
+.PHONY: clean cleanall iso-get iso-checksum iso-preseed udebs
diff --git a/.gitignore b/include/.gitignore
index 05b023b..05b023b 100644
--- a/.gitignore
+++ b/include/.gitignore
diff --git a/partition.sh b/include/partition.sh
index fb56ce7..fb56ce7 100755
--- a/partition.sh
+++ b/include/partition.sh
diff --git a/preseed.cfg b/preseed.cfg
new file mode 100644
index 0000000..7856628
--- /dev/null
+++ b/preseed.cfg
@@ -0,0 +1,57 @@
+# Preseed file
+#
+# Copyright 2013 Guilhem Moulin <guilhem@fripost.org>
+#
+# Licensed under the GNU GPL version 3 or higher.
+
+# Locales
+d-i debian-installer/locale string en_US.UTF-8
+d-i localechooser/supported-locales multiselect sv_SE.UTF-8
+d-i keymap skip-config
+
+# Debian archive mirror hostname (installer only):
+d-i mirror/http/hostname string ftp.se.debian.org
+
+# Assume the clock is UTC. Always use NTP.
+d-i clock-setup/utc boolean true
+d-i clock-setup/ntp boolean true
+d-i clock-setup/ntp-server string 0.se.pool.ntp.org
+d-i time/zone string Europe/Stockholm
+
+# Network
+d-i netcfg/choose_interface select auto
+d-i netcfg/hostname string eilift
+d-i netcfg/get_domain string guilhem.org
+#d-i netcfg/disable_autoconfig boolean true
+#d-i netcfg/get_ipaddress string 192.168.10.100
+#d-i netcfg/get_netmask string 255.255.255.0
+#d-i netcfg/get_gateway string 192.168.10.2
+#d-i netcfg/get_nameservers string 192.168.10.1
+#d-i netcfg/confirm_static boolean true
+
+# Users
+adduser adduser/homedir-permission boolean false
+d-i passwd/root-login boolean false
+d-i passwd/shadow boolean true
+d-i passwd/user-fullname string Guilhem Moulin
+d-i passwd/username string guilhem
+# TODO: should be generated by preseed.sh: echo ... | mkpasswd -s -H SHA-512
+d-i passwd/user-password-crypted password $6$QjLeZdW1O$9VymVDc5q6NctEylAqObvmP4S7FXk1ckCPaHua0JaiFSaTeTKoWxaP7bQoUWvzCPDY23Xqthg87QDBbaCY9BP0
+d-i passwd/user-default-groups string ssh
+
+# System
+popularity-contest popularity-contest/participate boolean true
+d-i base-installer/kernel/image string linux-image-amd64
+d-i base-installer/kernel/linux/initramfs-generators string initramfs-tools
+# A subset of 'standard' is interesting: tasksel --task-packages standard
+tasksel tasksel/first string
+d-i pkgsel/include string curl bind9-host git heirloom-mailx python-apt \
+ postfix vim-nox emacs23-nox
+d-i pkgsel/upgrade select safe-upgrade
+
+d-i preseed/early_command string anna-install fripost-partman fripost-postinst
+d-i preseed/late_command string /bin/in-target /usr/bin/update-alternatives --set editor /usr/bin/vim.nox
+d-i fripost/partition-script string /cdrom/include/partition.sh
+
+d-i fripost/wipe-device string none
+d-i fripost/initrd-ssh-port string 2222
diff --git a/preseed.sh b/preseed.sh
new file mode 100755
index 0000000..b3d8362
--- /dev/null
+++ b/preseed.sh
@@ -0,0 +1,93 @@
+#!/bin/sh
+#
+# Usage: preseed.sh preseeded.iso source.iso [udebs]
+#
+# Credits: https://wiki.debian.org/DebianInstaller/Preseed/EditIso
+# https://wiki.debian.org/DebianInstaller/Modify/CD
+#
+# Install with 'Advanced options > Automated install'
+
+set -ue
+
+newiso=$(readlink -f "$1")
+[ -e "$newiso" ] && rm -f "$newiso"
+
+iso="$2"
+test -r "$iso" || exit 1
+shift; shift
+pwd=$(pwd)
+
+for prog in fuseiso fusermount rsync md5sum genisoimage find; do
+ if ! which "$prog" >/dev/null; then
+ echo "Error: Missing $prog" >&2
+ exit 1
+ fi
+done
+
+mountdir=$(mktemp -d)
+fuseiso "$iso" "$mountdir"
+
+isoeditdir=$(mktemp -d)
+rsync -aH --exclude=TRANS.TBL --chmod=u+w "$mountdir"/ "$isoeditdir"/
+
+fusermount -u "$mountdir"
+rmdir "$mountdir"
+
+cp preseed.cfg "$isoeditdir/"
+md5sum ./preseed.cfg >> "$isoeditdir/md5sum.txt"
+
+isolinux=isolinux/adtxt.cfg
+sed -ri "s@^\s+append\s(.*\s)?auto=true\b@& file=/cdrom/preseed.cfg @" \
+ "$isoeditdir/$isolinux"
+# ^ no need to update the checksum, $isolinux is not in './md5sum.txt'.
+
+mkdir "$isoeditdir/include"
+rsync -aL ./include/ "$isoeditdir/include"/
+find ./include \( \! -name '.*' -a -type f \) -print0 | \
+ xargs -r0 md5sum >> "$isoeditdir/md5sum.txt"
+
+# TODO: that's ugly
+dist=$(for x in "$isoeditdir"/dists/*; do [ -h "$x" ] && continue; [ -d "$x" ] && echo ${x##*/} && break; done)
+arch=$(for x in "$isoeditdir/dists/$dist/main"/binary-*; do test -d "$x" && echo ${x##*/binary-} && break; done)
+packages="dists/$dist/main/debian-installer/binary-$arch/Packages"
+while [ $# -gt 0 ]; do
+ cd "${1%%_*}-udeb"; shift
+ name="$(sed -n 's/Package:\s\s*//p' ./debian/control)"
+ udeb=$(cut -d' ' -f1,1 ./debian/files)
+ dir="pool/main/$(expr substr "$name" 1 1)/$name"
+ mkdir -p "$isoeditdir/$dir/"
+ cp ../"$udeb" "$isoeditdir/$dir/"
+
+ cat "./debian/$name/DEBIAN/control" >> "$isoeditdir/$packages"
+ echo "Filename: $dir/$udeb" >> "$isoeditdir/$packages"
+ echo "MD5sum: $(md5sum ../"$udeb" | cut -d' ' -f1,1)" >> "$isoeditdir/$packages"
+ echo "SHA1: $(sha1sum ../"$udeb" | cut -d' ' -f1,1)" >> "$isoeditdir/$packages"
+ echo "SHA256: $(sha256sum ../"$udeb" | cut -d' ' -f1,1)" >> "$isoeditdir/$packages"
+ echo >> "$isoeditdir/$packages"
+
+ cd "$isoeditdir"
+ md5sum "./$dir/$udeb" >> "$isoeditdir/md5sum.txt"
+ cd "$pwd"
+done
+
+cd "$isoeditdir"
+gzip -fk ./"$packages"
+
+md5sums=$(mktemp)
+while read sum file; do
+ if [ "$file" = "./${packages}" -o \
+ "$file" = "./${packages}.gz" ]; then
+ md5sum "$file"
+ else
+ echo "$sum $file"
+ fi
+done < ./md5sum.txt > "$md5sums"
+mv "$md5sums" "$isoeditdir/md5sum.txt"
+
+genisoimage -o "$newiso" -quiet -r -J \
+ -no-emul-boot -boot-load-size 4 \
+ -boot-info-table \
+ -b isolinux/isolinux.bin \
+ -c isolinux/boot.cat \
+ ./
+rm -rf "$isoeditdir"
diff --git a/src/.gitignore b/src/.gitignore
new file mode 100644
index 0000000..85b61ee
--- /dev/null
+++ b/src/.gitignore
@@ -0,0 +1,3 @@
+*.udeb
+*.build
+*.changes
diff --git a/src/fripost-partman-udeb/Makefile b/src/fripost-partman-udeb/Makefile
new file mode 100644
index 0000000..b603c83
--- /dev/null
+++ b/src/fripost-partman-udeb/Makefile
@@ -0,0 +1,13 @@
+CC ?= gcc
+CFLAGS ?= -Wall -x c -s
+
+LIBS = lib/stdbuf.so
+
+all: ${LIBS}
+
+%.so: %.c
+ #TODO: multiarch (-m32/-m64)
+ ${CC} ${CFLAGS} $< -fPIC -shared -o $@
+
+clean:
+ rm -f ${LIBS}
diff --git a/src/fripost-partman-udeb/base.sh b/src/fripost-partman-udeb/base.sh
new file mode 100644
index 0000000..114e678
--- /dev/null
+++ b/src/fripost-partman-udeb/base.sh
@@ -0,0 +1,527 @@
+# Functions commonly used by fripost-partman shell scripts
+#
+# Copyright 2013 Guilhem Moulin <guilhem@fripost.org>
+#
+# Licensed under the GNU GPL version 3 or higher.
+
+true ${DEBIAN_HAS_FRONTEND:=} ${DEBCONF_REDIR:=}
+. /usr/share/debconf/confmodule
+
+# TODO:
+# * support sofware RAID (mdadm)
+# * encryption without SSH daemon (eg when /home is on a separate device)
+# * encryption of multiple disks with the same key (eg / on a software raid)
+
+
+# Log a message.
+log() {
+ logger -t fripost -- "$@"
+}
+
+# Log a fatal error and quit.
+fatal() {
+ logger -t fripost -p user.err -- "$@"
+ exit 1
+}
+
+# Ensure stdout is opened with line buffering. If some day stdbuf(1) is
+# available in busybox, we should replace the LD_PRELOAD by 'stdbuf -oL -eL'.
+stdbuf() {
+ LD_PRELOAD=/lib/fripost-partman/stdbuf.so "$@"
+}
+
+# Wait for a device to be created
+wait_for_device() {
+ local device="$1" timeout=40
+
+ until [ -b "$device" -o $timeout -le 0 ]; do
+ log "Waiting for ${device}..."
+ sleep 0.25
+ timeout=$(( $timeout - 1 ))
+ done
+ [ -b "$device" ] || fatal "Error: $device not found!"
+}
+
+
+##############################################################################
+# Wipe the disk (unless d-i's 'fripost/wipe-device' is 'none')
+#
+# Usage: fripost_wipe <device>
+
+fripost_wipe() {
+ local device="$1" source bs=8192 blockdir size wipe fifo pid
+ blockdir="/sys/block/${device#/dev/}"
+
+ db_get fripost/wipe-device
+ if [ "$RET" = none ]; then
+ log "Not wiping $device"
+ return 0
+ fi
+
+ source="/dev/$RET"
+ log "Want to wipe $device using source $source"
+ [ -b "$device" -a -d "$blockdir" -a -c "$source" ] || \
+ fatal "Invalid device $device or source $source"
+
+ size=$(( `cat $blockdir/size` * `cat $blockdir/queue/physical_block_size` ))
+
+ wipe="dd if=$source of=$device bs=$bs"
+ db_subst fripost/wipe-device_progress_title DISK "$device"
+ db_subst fripost/wipe-device_progress_title SIZE "$size"
+ if [ "$source" = /dev/zero ]; then
+ db_subst fripost/wipe-device_progress_title WHAT "zeroes"
+ elif [ "$source" = /dev/random -o "$source" = /dev/urandom ]; then
+ db_subst fripost/wipe-device_progress_title WHAT "bytes of random data"
+ else
+ db_subst fripost/wipe-device_progress_title WHAT "bytes"
+ fi
+ db_progress START 0 $(( $size / $bs )) fripost/wipe-device_progress_title
+ db_subst fripost/wipe-device_progress_info COMMAND "$wipe"
+ db_progress INFO fripost/wipe-device_progress_info
+
+ fifo=$(mktemp -u)
+ /bin/mknod "$fifo" p || exit 1
+ trap 'echo kill $pid' EXIT
+ $wipe 2> "$fifo" & pid=$!
+ heartbeat $pid USR1 &
+
+ local n records dir
+ while read -u 7 n records dir; do
+ [ "$records" = records -a "$dir" = out ] && db_progress SET ${n%+*}
+ done 7< "$fifo"
+ db_progress SET $(( $size / $bs )); sleep 0.25
+
+ rm -f "$fifo"
+ trap '' EXIT
+
+ db_progress STOP
+ db_unregister fripost/wipe-device_progress_title
+ db_unregister fripost/wipe-device_progress_info
+}
+
+heartbeat () {
+ local pid=$1 sig=${2:-SIGHUP} sleep=${3:-1}
+ until false; do
+ sleep $sleep
+ /bin/kill -$sig $pid 2>/dev/null || break
+ done
+}
+
+
+
+##############################################################################
+# Partitioning
+#
+# Usage: fripost_mkpart <device> <name> <size in bytes or %> [flag | +flag | -flag | ...]
+#
+# Prints the bloc device for the new partition. <size> can be given
+# using SI prefixes T,G,M, or k. If <size> is a percentage, it is
+# relative to the free capacity.
+
+fripost_mkpart() {
+ local device="$1" name="$2" size="$3" grain=$(( 256*32 )) offset bs
+ local start stop part flag free
+ # TODO: names are supported on GPT only. What is the second argument
+ # of mkpart on msdos?
+
+ bs=$(cat /sys/block/${device#/dev/}/queue/physical_block_size)
+
+ if /sbin/parted -sm "$device" p | grep -q '^[1-9][0-9]*:'; then
+ # The last offset, in sector; it is *always* supposed to be aligned.
+ start=$( /sbin/parted -sm "$device" u s p \
+ | grep '^[1-9][0-9]*:' \
+ | sort -t: -nk2,2 \
+ | tail -1 \
+ | sed -r 's/^[1-9][0-9]*:[^:]*:([1-9][0-9]*)s:.*/\1/' )
+ start=$(( 1 + $start ))
+ else
+ # There are no partitions yet
+ offset=$(cat /sys/block/${device#/dev/}/alignment_offset)
+ if [ $offset -eq 0 ]; then
+ # 64 is arbitrary here; $grain may be better since aligned,
+ # but the 1st partition is typically /boot or something
+ # without heavy IO, so choosing a smaller value means we get
+ # more space without significant performance penalty
+ start=64
+ else
+ start=$(( $offset / $bs ))
+ fi
+ fi
+
+ # Remove the SI prefix, or compute the size relative to a percentage
+ case "$size" in
+ *T) size=$(( ${size%T} * 1024**4 ));;
+ *G) size=$(( ${size%G} * 1024**3 ));;
+ *M) size=$(( ${size%M} * 1024**2 ));;
+ *K) size=$(( ${size%K} * 1024 ));;
+ *%) free=$(( `cat /sys/block/${device#/dev/}/size` - 1 - $start ))
+ size=$(( $bs * $free * ${size%\%} / 100 ))
+ ;;
+ *) fatal "Unknown size $size" ;;
+ esac
+
+ # Round toward 0 to preserve the alignement
+ stop=$(( $start + $size / $bs ))
+ stop=$(( $stop - $stop % $grain - 1 ))
+ log "Creating partition '$name' on $device, between sectors $start and $stop"
+ [ $start -ge $stop ] && fatal "Cannot create partition: $start >= $stop"
+ /sbin/parted -a minimal -s $device mkpart "$name" ${start}s ${stop}s
+
+ # The partition index that is to be created
+ part=$( /sbin/parted -sm $device u s p \
+ | grep -m1 "^[0-9]:${start}s:" \
+ | sed 's/:.*//' )
+
+ while [ $# -gt 3 ]; do
+ flag="$4"
+ log "Partition flag for ${device}${part} ($name): $flag"
+ case "$flag" in
+ +*) /sbin/parted -s $device set $part "${flag#+}" on ;;
+ -*) /sbin/parted -s $device set $part "${flag#-}" off ;;
+ *) /sbin/parted -s $device toggle $part "$flag" ;;
+ esac
+ shift
+ done
+
+ wait_for_device "${device}${part}"
+ echo ${device}${part}
+}
+
+
+
+##############################################################################
+# Encryption
+#
+# Usage: fripost_encrypt <device> <name> [<cryptsetup options>]
+
+fripost_encrypt() {
+ local device="$1" name="$2" keyfile sshHostKey import=/cdrom/include
+ local fifo pid
+ shift; shift
+ keyfile=$(mktemp) || exit 1
+
+ log "Encryting device $device and sets up a mapping $name"
+
+ db_input high fripost/encryption-password || true
+ db_go
+ db_get fripost/encryption-password
+
+ if [ -n "$RET" ]; then
+ log "The password can be found from debconf (hey, that's insecure!)"
+ # Since we're using the builtin, the password shouldn't be
+ # visible in ps(1).
+ echo -n "$RET" > "$keyfile"
+ db_set fripost/encryption-password ''
+
+ else
+ log "Starting a SSH daemon to slurp the volume key..."
+ local type=rsa
+ db_subst fripost/ssh-keypair-generation_progress_title TYPE $type
+ db_progress START 0 1 fripost/ssh-keypair-generation_progress_title
+
+ mkdir -pm0755 /etc/ssh/
+ sshHostKey=/etc/ssh/ssh_host_rsa_key
+ /usr/bin/ssh-keygen -b 4096 -t $type -N '' -C $sshHostKey -f $sshHostKey
+ db_progress SET 1; sleep 0.25
+ db_progress STOP
+ db_unregister fripost/ssh-keypair-generation_progress_title
+
+ cat > /etc/ssh/sshd_config <<- EOF
+ Port 22
+ Protocol 2
+ HostKey $sshHostKey
+ UsePrivilegeSeparation no
+
+ PasswordAuthentication no
+ ChallengeResponseAuthentication no
+ HostbasedAuthentication no
+ PubkeyAuthentication yes
+
+ PermitRootLogin yes
+ AllowUsers root
+ StrictModes yes
+
+ AllowAgentForwarding no
+ AllowTcpForwarding no
+ ForceCommand /bin/cat >$keyfile
+ EOF
+
+ # Populate the authorized keys.
+ [ -d ~root/.ssh ] || mkdir -m0700 ~root/.ssh
+ copy_authorized_keys $import/authorized_keys ~root/.ssh/authorized_keys 'no-pty'
+
+ # Start the SSH daemon
+ touch /var/log/lastlog
+ /usr/sbin/sshd
+
+ # Tell the user we're ready
+ db_subst fripost/encryption-slurpkey_text IPv4 "$(getIPv4)"
+ db_subst fripost/encryption-slurpkey_text SSHFPR_SERVER \
+ "$(/usr/bin/ssh-keygen -lf $sshHostKey)"
+ db_subst fripost/encryption-slurpkey_text SSHFPR_AUTHORIZED \
+ "$(sshfprs ~root/.ssh/authorized_keys ' - ')"
+
+ # Anything sent to the SSH is stored into $keyfile, which is our LUKS key.
+ until test -s "$keyfile"; do
+ db_settitle fripost/encryption-slurpkey_title
+ db_input critical fripost/encryption-slurpkey_text
+ db_go
+ done
+
+ # Kill the daemon, we're done
+ log "Killing the SSH daemon..."
+ kill `cat /var/run/sshd.pid` || true
+ fi
+
+ # Load dm-crypt
+ /sbin/dmsetup targets | cut -d' ' -f1 | grep -q '^crypt$' \
+ || /sbin/modprobe -v dm_crypt
+
+ log "cryptsetup options: $@"
+ db_progress START 0 100 fripost/cryptsetup-genkey_progress_title
+ db_progress INFO fripost/cryptsetup-genkey_progress_info
+
+ fifo=$(mktemp -u)
+ /bin/mknod "$fifo" p || exit 1
+ trap 'echo kill $pid' EXIT
+ stdbuf /sbin/cryptsetup -q "$@" --key-file="$keyfile" luksFormat "$device" \
+ | stdbuf sed -nr 's/^Generating key \(([0-9]+)% done\)\.$/\1/p' > "$fifo" & pid=$!
+
+ local n
+ while read -u 7 n; do
+ db_progress SET $n
+ done 7< "$fifo"
+ db_progress SET 100; sleep 0.25
+
+ rm -f "$fifo"
+ trap '' EXIT
+
+ db_progress STOP
+ db_unregister fripost/cryptsetup-genkey_progress_title
+ db_unregister fripost/cryptsetup-genkey_progress_info
+
+ # Open the LUKS device and set up the mapping
+ /sbin/cryptsetup --key-file="$keyfile" luksOpen "$device" "$name"
+
+ log "Removing the key file"
+ rm -f "$keyfile" # We are on a ramdisk, so it's good enough to unlink(2)
+
+ # Add an entry to the crypttab
+ printf "%-15s %-41s %-15s %s\n" \
+ "$name" UUID=$(/bin/block-attr --uuid "$device") none luks \
+ >> /tmp/crypttab
+
+ local m _
+ [ -d /var/lib/fripost ] || mkdir /var/lib/fripost
+ # The modules required to fire up dropbear and start cryptsetup in the ramdisk.
+ echo dm_crypt > /tmp/initramfs-modules
+ while read m _; do /sbin/modinfo -F filename "$m"; done < /proc/modules \
+ | sed -nr "s@^/lib/modules/`uname -r`/kernel/((arch/[^/]+/)?crypto|drivers/(ata|scsi))(/.*)?/([^/]+)\.ko\$@\5@p" \
+ >> /var/lib/fripost/initrd-modules
+ /bin/apt-install busybox cryptsetup || true
+
+ wait_for_device "/dev/mapper/$name"
+}
+
+
+# Like ssh-keygen -lf, but for a file such as authorized_keys, which
+# may contain multiple keys.
+#
+# Usage: sshfprs.sh file [prefix]
+
+sshfprs() {
+ local file="$1" prefix="${2:-}" pk
+
+ while read pk; do
+ # /usr/bin/ssh-keygen can't read from STDIN, and the '<<<' is
+ # not POSIX, so we save each pubkey in a temporary file
+ pkf=$(mktemp)
+ echo "$pk" > "$pkf"
+ echo "${prefix}$(/usr/bin/ssh-keygen -lf $pkf)"
+ rm -f "$pkf"
+ done < "$file"
+}
+
+# Copy an authorized_keys file, possibly adding some options. The input
+# format is sshd(8)'s; see the section called "AUTHORIZED_KEYS FILE
+# FORMAT" in the manpage. The character '#' cannot occur in the options.
+
+copy_authorized_keys() {
+ local from="$1" to="$2"
+ if [ $# -gt 2 ]; then
+ sed -r "s#^([^#]+\s)?(ssh-(dss|rsa)|ecdsa-sha2-nistp(256|384|521))\s#$3 \2 #" \
+ "$from" > "$to"
+ else
+ cp "$from" "$to"
+ fi
+ chmod 0600 "$to"
+}
+
+
+
+##############################################################################
+# Add a progress bar to mkfs(8).
+#
+# Usage: fripost_mkfs <type> <device> [<options>]
+
+fripost_mkfs() {
+ local type="$1" device="$2" fifo pid line stage step total=
+ shift; shift
+
+ log "Formatting $device as $type; options $@"
+ db_subst fripost/mkfs_progress_title DEVICE "$device"
+ db_subst fripost/mkfs_progress_title TYPE "$type"
+ wait_for_device "$device"
+
+ fifo=$(mktemp -u)
+ /bin/mknod "$fifo" p || exit 1
+ trap 'echo kill $pid' EXIT
+ /sbin/mkfs."$type" "$@" "$device" | tr '\b' '\n' > "$fifo" & pid=$!
+
+ while read -u 7 line; do
+ # XXX: The parsing has been tested with mkfs.ext{2,3,4} only.
+ case "$line" in
+ *:*/*)
+ [ -z "$total" ] || db_progress STOP
+
+ stage="${line%: *}"
+ step="${line##*: }"
+ log "mkfs(8) stage '$stage', $step steps"
+
+ total="${step#*/}"
+ db_progress START 0 $total fripost/mkfs_progress_title
+ db_progress SET ${step%/*}
+
+ db_subst fripost/mkfs_progress_info STAGE "$stage"
+ db_progress INFO fripost/mkfs_progress_info
+ ;;
+ */$total)
+ [ -z "$total" ] || db_progress SET ${line%/*}
+ ;;
+ done)
+ [ -z "$total" ] || db_progress SET $total
+ ;;
+ esac
+ done 7< "$fifo"
+
+ rm -f "$fifo"
+ trap '' EXIT
+
+ [ -z "$total" ] || db_progress STOP
+ db_unregister fripost/mkfs_progress_title
+ db_unregister fripost/mkfs_progress_info
+}
+
+
+##############################################################################
+# Set up the fstab
+#
+# Usage: fripost_fstab <device> <mountpoint> <type> [<options>]
+#
+# Note: Don't forget to run 'fripost_mount_partitions' after the last
+# call to 'fripost_fstab'.
+
+fripost_fstab() {
+ local device="$1" mp="$2" type="$3" options="${4:-defaults}" pass
+
+ # TODO: EFI should be set with pass 1
+ if [ "$mp" = / ]; then
+ log "Got root device, $device"
+ pass=1
+ elif [ "$type" = swap ]; then
+ log "Got swap device, $device"
+ pass=0
+ else
+ log "Got other device, $device -> $mp"
+ pass=2
+ fi
+
+ # Add an entry to the fstab
+ fripost_fstab_addentry $device $mp $type $options 0 $pass
+}
+
+fripost_fstab_addentry() {
+ local device=$1 mp=$2 type=$3 options=$4 dump=$5 pass=$6
+ local fstab=/tmp/fstab
+ local entry="%-41s %-15s %-7s %-31s %-7s %s\n"
+ log "Adding fstab entry $device -> $mp"
+
+ if ! [ -s $fstab -a -f $fstab ]; then
+ # No fstab has bee created yet. We copy the header from
+ # /lib/partman/finish.d/39create_fstab_header
+ cat > $fstab <<-EOF
+ # /etc/fstab: static file system information.
+ #
+ # Use 'blkid' to print the universally unique identifier for a device;
+ # this may be used with UUID= as a more robust way to name devices that
+ # works even if disks are added and removed. See fstab(5).
+ #
+ EOF
+ printf "$entry" '# <file system>' '<mount point>' '<type>' \
+ '<options>' '<dump>' '<pass>' \
+ >> $fstab
+ fi
+
+ # Always use UUIDs
+ local uuid=$(/bin/block-attr --uuid "$device")
+ if [ -z "$uuid" ]; then
+ log "Warning: Block device $device has no UUID!"
+ printf "$entry" "$device" $mp $type $options $dump $pass >> $fstab
+ else
+ log "Block device $device has UUID $uuid"
+ printf "$entry" "UUID=$uuid" $mp $type $options $dump $pass >> $fstab
+
+ # Fix udev's UUID mapping
+ if ! [ -h /dev/disk/by-uuid/"$uuid" ]; then
+ device=$(/bin/mapdevfs "$device")
+ log "Adding a symlink UUID $uuid -> $device"
+ ln -s ../../"${device#/dev/}" /dev/disk/by-uuid/"$uuid"
+ fi
+ fi
+}
+
+
+
+##############################################################################
+# Mount all entries in the fstab
+#
+# Usage: fripost_mount_partitions
+
+fripost_mount_partitions() {
+ local cdrom uuid mp type options _
+
+ # sort(1), to ensure that roots are mounted earlier, regardless of
+ # where they appear in the file (eg, /boot can appear before /).
+ sed -e 's/#.*//' -e '/^\s*$/d' -e 's/\s\s*/ /g' /tmp/fstab \
+ | grep -v '\s0$' \
+ | sort -t' ' -k2,2 \
+ | while read uuid mp type options _; do
+ local dev=$(/sbin/blkid -U "${uuid#UUID=}")
+ log "Found fstab entry: $dev -> $mp"
+ wait_for_device "$dev"
+ if [ "$type" = swap ]; then
+ /sbin/swapon "$dev"
+ elif [ / = $(expr substr "$mp" 1 1) ]; then
+ mkdir "/target$mp"
+ /bin/mount -t "$type" -o "$options" "$dev" "/target$mp"
+ fi
+ done
+
+ # Post-installation scripts may use the install CD as a local mirror
+ # for APT packages. TODO: What if it was a USB stick? A netboot?
+ cdrom=$( sed -rn 's#^(\S+) /cdrom.*#\1#p' /proc/mounts \
+ | grep -m1 -Ev '^/dev/(loop|sd[a-z])' )
+ [ -n "$cdrom" ] || fatal "Error: Is /cdrom a mountpoint?"
+ fripost_fstab_addentry "$cdrom" /media/cdrom0 udf,iso9660 user,noauto 0 0
+ mkdir -p /target/media/cdrom0
+ ln -s cdrom0 /target/media/cdrom
+
+ # Move the fstab and crypttab where they belong
+ [ -d /target/etc ] || mkdir /target/etc
+ mv /tmp/fstab /target/etc/fstab
+ [ \! -f /tmp/crypttab ] || mv /tmp/crypttab /target/etc/crypttab
+}
+
+getIPv4() {
+ /bin/ip addr show "${1:-eth0}" | sed -nr 's/^\s+inet\s([0-9.]{4,32}).*/\1/p'
+}
diff --git a/src/fripost-partman-udeb/debian/changelog b/src/fripost-partman-udeb/debian/changelog
new file mode 100644
index 0000000..6146216
--- /dev/null
+++ b/src/fripost-partman-udeb/debian/changelog
@@ -0,0 +1,5 @@
+fripost-partman (0.0.0) unstable; urgency=low
+
+ * Tests
+
+ -- Guilhem Moulin <guilhem@fripost.org> Wed, 09 Oct 2013 17:33:16 +0200
diff --git a/src/fripost-partman-udeb/debian/compat b/src/fripost-partman-udeb/debian/compat
new file mode 100644
index 0000000..7f8f011
--- /dev/null
+++ b/src/fripost-partman-udeb/debian/compat
@@ -0,0 +1 @@
+7
diff --git a/src/fripost-partman-udeb/debian/control b/src/fripost-partman-udeb/debian/control
new file mode 100644
index 0000000..043fa49
--- /dev/null
+++ b/src/fripost-partman-udeb/debian/control
@@ -0,0 +1,21 @@
+Source: fripost-partman
+Section: debian-installer
+Priority: optional
+Maintainer: Guilhem Moulin <guilhem@fripost.org>
+Build-Depends: debhelper (>= 7)
+
+Package: fripost-partman
+XC-Package-Type: udeb
+Architecture: all
+Depends: cdebconf-udeb, parted-udeb, xfsprogs-udeb, hw-detect, md-modules,
+ mdadm-udeb, lvm2-udeb, dmsetup-udeb, ntfstools-udeb, xfs-modules,
+ ext2-modules, ext3-modules, openssh-server-udeb, cryptsetup-udeb,
+ crypto-dm-modules, ${misc:Depends}
+Provides: created-fstab, made-filesystems, mounted-partitions,
+ partitioned-harddrives
+Description: Partition Hard Drives using shell scripts.
+ .
+ Warning: This module *will* wipe your disk if you ask it to do so, without
+ giving you the chance to back out. Do not use this on systems you care about
+ unless you've made thorough tests with Virtual Machines.
+XB-Installer-Menu-Item: 4199
diff --git a/src/fripost-partman-udeb/debian/copyright b/src/fripost-partman-udeb/debian/copyright
new file mode 100644
index 0000000..4e26ce2
--- /dev/null
+++ b/src/fripost-partman-udeb/debian/copyright
@@ -0,0 +1,7 @@
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Source: native package
+
+Files: *
+Copyright: © 2013 Guilhem Moulin <guilhem@fripost.org>
+License: GPL-3+
+
diff --git a/src/fripost-partman-udeb/debian/install b/src/fripost-partman-udeb/debian/install
new file mode 100644
index 0000000..885868e
--- /dev/null
+++ b/src/fripost-partman-udeb/debian/install
@@ -0,0 +1 @@
+base.sh lib/*.so lib/fripost-partman
diff --git a/src/fripost-partman-udeb/debian/postinst b/src/fripost-partman-udeb/debian/postinst
new file mode 100755
index 0000000..6ba238e
--- /dev/null
+++ b/src/fripost-partman-udeb/debian/postinst
@@ -0,0 +1,25 @@
+#! /bin/sh
+
+set -ue
+
+. /lib/fripost-partman/base.sh
+
+log "Starting..."
+db_input high fripost/partition-script || true
+db_go
+db_get fripost/partition-script
+script=/"${RET#/}"
+
+[ -f "$script" -a -x "$script" ] || \
+ fatal "$script does not exist, or is not executable."
+
+log "Running $script"
+log-output -t fripost-partman "$script"
+
+rv=$?
+if [ $rv -ne 0 ]; then
+ log "Partitioning script failed; exited with $rv"
+ exit $rv
+fi
+
+log "Partitioning appears to have completed successfully."
diff --git a/src/fripost-partman-udeb/debian/rules b/src/fripost-partman-udeb/debian/rules
new file mode 100755
index 0000000..cbe925d
--- /dev/null
+++ b/src/fripost-partman-udeb/debian/rules
@@ -0,0 +1,3 @@
+#!/usr/bin/make -f
+%:
+ dh $@
diff --git a/src/fripost-partman-udeb/debian/templates b/src/fripost-partman-udeb/debian/templates
new file mode 100644
index 0000000..00377a5
--- /dev/null
+++ b/src/fripost-partman-udeb/debian/templates
@@ -0,0 +1,84 @@
+Template: debian-installer/fripost-partman/title
+Type: text
+Description: Partition disks using a shell script
+
+Template: fripost/partition-script
+Type: text
+Description: Which script should be used for partitioning?
+Extended_description: The path should be absolute, and the script must
+ be executable.
+
+Template: fripost/wipe-device
+Type: select
+Default: zero
+Choices: none, zero, urandom, random
+Description: Which kind of data fill the disk with before encryption?
+Extended_description: 'none' means disks will NOT wiped, otherwise use
+ /dev/{zero,urandom,random} as the source data to fill disks with.
+ Beware that the later two may drain the entropy pool of the system!
+
+Template: fripost/wipe-device_progress_title
+Type: text
+Description: Filling ${DISK} with ${SIZE} ${WHAT}
+
+Template: fripost/wipe-device_progress_info
+Type: text
+Description: ${COMMAND}
+
+Template: fripost/encrypt
+Type: boolean
+Default: true
+Description: Should the system disk be fully encrypted? (Excluding /boot.)
+
+Template: fripost/encryption-password
+Type: password
+Default:
+Description: Password for full-disk encryption?
+Extended_description: If left empty, a SSH daemon will be fired and the
+ automatic install will be interupted, waiting for the user to dump the
+ password on the standard input.
+
+Template: fripost/ssh-keypair-generation_progress_title
+Type: text
+Description: Generating public/private ${TYPE} key pair
+
+Template: fripost/encryption-slurpkey_title
+Type: note
+Description: Waiting for passphrase
+
+Template: fripost/encryption-slurpkey_text
+Type: text
+Description: Press 'continue' once you have sent the key
+ You now need to send the encryption key for the LUKS/dm-crypt volume to
+ this special-purpose SSH server:
+ .
+ ssh -o UserKnownHostsFile=/dev/null -T root@${IPv4} < /path/to/key
+ .
+ To defeat MiTM-attacks, please ensure that the server fingerprint matches
+ .
+ ${SSHFPR_SERVER}
+ .
+ Key(s) that are granted access have the following fingerprint:
+ .
+ ${SSHFPR_AUTHORIZED}
+ .
+ Note: This server is ephemeral, and will be replaced with a full-blown
+ daemon toward the end of the installation. Using /dev/null as the
+ Known Hosts File is meant to tell the SSH client not to remember its
+ public key.
+
+Template: fripost/cryptsetup-genkey_progress_title
+Type: text
+Description: Generating volume key
+
+Template: fripost/cryptsetup-genkey_progress_info
+Type: text
+Description: This will take a while if it drains the entropy pool
+
+Template: fripost/mkfs_progress_title
+Type: text
+Description: Formatting ${DEVICE} as ${TYPE}
+
+Template: fripost/mkfs_progress_info
+Type: text
+Description: ${STAGE}
diff --git a/src/fripost-partman-udeb/lib/stdbuf.c b/src/fripost-partman-udeb/lib/stdbuf.c
new file mode 100644
index 0000000..13e6c06
--- /dev/null
+++ b/src/fripost-partman-udeb/lib/stdbuf.c
@@ -0,0 +1,11 @@
+/* All credits to https://lists.gnu.org/archive/html/bug-coreutils/2008-11/msg00138.html
+ * Cf. also http://www.pixelbeat.org/programming/stdio_buffering/
+ * http://git.savannah.gnu.org/gitweb/?p=coreutils.git;a=blob;f=src/stdbuf.c;h=2500c300147f30aa5d2d99fd29b5865637a11290;hb=HEAD
+ */
+
+#include <stdio.h>
+
+__attribute__ ((constructor)) void
+cah9mion4ocim6ip () {
+ setvbuf (stdout, NULL, _IOLBF, 0);
+}
diff --git a/src/fripost-postinst-udeb/debian/changelog b/src/fripost-postinst-udeb/debian/changelog
new file mode 100644
index 0000000..c1ea4fd
--- /dev/null
+++ b/src/fripost-postinst-udeb/debian/changelog
@@ -0,0 +1,5 @@
+fripost-postinst (0.0.0) unstable; urgency=low
+
+ * Tests
+
+ -- Guilhem Moulin <guilhem@fripost.org> Wed, 17 Oct 2013 04:32:31 +0200
diff --git a/src/fripost-postinst-udeb/debian/compat b/src/fripost-postinst-udeb/debian/compat
new file mode 100644
index 0000000..7f8f011
--- /dev/null
+++ b/src/fripost-postinst-udeb/debian/compat
@@ -0,0 +1 @@
+7
diff --git a/src/fripost-postinst-udeb/debian/control b/src/fripost-postinst-udeb/debian/control
new file mode 100644
index 0000000..e173159
--- /dev/null
+++ b/src/fripost-postinst-udeb/debian/control
@@ -0,0 +1,11 @@
+Source: fripost-postinst
+Section: debian-installer
+Priority: optional
+Maintainer: Guilhem Moulin <guilhem@fripost.org>
+Build-Depends: debhelper (>= 7)
+
+Package: fripost-postinst
+XC-Package-Type: udeb
+Architecture: all
+Depends: fripost-partman, ${misc:Depends}
+Description: Post-install scripts (e.g., install dropbear in the initramfs)
diff --git a/src/fripost-postinst-udeb/debian/copyright b/src/fripost-postinst-udeb/debian/copyright
new file mode 100644
index 0000000..4e26ce2
--- /dev/null
+++ b/src/fripost-postinst-udeb/debian/copyright
@@ -0,0 +1,7 @@
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Source: native package
+
+Files: *
+Copyright: © 2013 Guilhem Moulin <guilhem@fripost.org>
+License: GPL-3+
+
diff --git a/src/fripost-postinst-udeb/debian/install b/src/fripost-postinst-udeb/debian/install
new file mode 100644
index 0000000..5426071
--- /dev/null
+++ b/src/fripost-postinst-udeb/debian/install
@@ -0,0 +1,2 @@
+finish-install.d/* /usr/lib/finish-install.d
+sshd_config /var/lib/fripost
diff --git a/src/fripost-postinst-udeb/debian/rules b/src/fripost-postinst-udeb/debian/rules
new file mode 100755
index 0000000..cbe925d
--- /dev/null
+++ b/src/fripost-postinst-udeb/debian/rules
@@ -0,0 +1,3 @@
+#!/usr/bin/make -f
+%:
+ dh $@
diff --git a/src/fripost-postinst-udeb/debian/templates b/src/fripost-postinst-udeb/debian/templates
new file mode 100644
index 0000000..5385ce9
--- /dev/null
+++ b/src/fripost-postinst-udeb/debian/templates
@@ -0,0 +1,93 @@
+Template: base-installer/progress/fripost
+Type: text
+Description: ${WHAT}
+
+Template: fripost/initrd-ssh-port
+Type: string
+Default: 22
+Description: On which [address:]port should dropbear listen?
+Extended_description: If port is a range (e.g., 1024-65535), a random
+ port in that range is chosen. Leaving the question empty is equivalent
+ to specifying the range of registered port 1024-49151. This is only
+ used for remote (SSH) unlocking of encrypted disks.
+
+Template: fripost/dropbear-use-openssh-key
+Type: boolean
+Default: false
+Description: Use the same key for dropbear and OpenSSH?
+Extended_description: If False, generate a dedicated key for dropbear.
+
+Template: fripost/activate-selinux
+Type: boolean
+Default: true
+Description: Install and activate (in enforcing mode) SELinux?
+Extended_description: Note that activating SELinux requires a dummy
+ reboot to label all files. So if you have full-disk encryption, you'll
+ have to send the password twice to dropbear.
+
+Template: fripost/keep-media-directory
+Type: boolean
+Default: false
+Description: Keep /media and its kids' entries in the fstab?
+Extended_description: /media (and its related entries in the fstab)
+ can safely be removed on a headless server.
+
+Template: fripost/sshd-fprs_title
+Type: text
+Description: Reboot in progress
+
+Template: fripost/sshd-fprs_text
+Type: note
+Description: Press 'continue' to reboot on the new system
+ We are done! After rebooting you should be able to log in into your
+ new machine:
+ .
+ ssh ${USER}@${IPv4}
+ .
+ To defeat MiTM-attacks, please ensure (for instance by trying to log in
+ right now, although it won't be successful before the next reboot) that
+ the server's public key has the following fingerprint
+ .
+ ${SSHFPR_SERVER}
+ .
+ To unlock the encrypted disk, you need to send the key to the SSH
+ daemon living in in the initrd:
+ .
+ ssh -p ${PORT} -T root@${IPv4} < /path/to/key
+ .
+ An attacker successfully mounting a MiTM-attack could get hold of the
+ encryption key! It is crucial that you match this (single purpose)
+ server's fingerprint against
+ .
+ ${SSHFPR_INITRD}
+ .
+ Key(s) that are granted access to these two servers have the following
+ fingerprint:
+ .
+ ${SSHFPR_AUTHORIZED}
+
+Template: fripost/sshd-fprs-nodropbear_text
+Type: note
+Description: Press 'continue' to reboot on the new system
+ We are done! After rebooting you should be able to log in into your new
+ machine:
+ .
+ ssh ${USER}@${IPv4}
+ .
+ To defeat MiTM-attacks, please ensure (for instance by trying to log in
+ right now, although it won't be successful before the next reboot) that
+ the server's public key has the following fingerprint
+ .
+ ${SSHFPR_SERVER}
+ .
+ Key(s) that are granted access to the server have the following
+ fingerprint:
+ .
+ ${SSHFPR_AUTHORIZED}
+
+Template: fripost/final-notice
+Type: boolean
+Default: true
+Description: Display the final notice before rebooting?
+Extended_description: It's good to show SSH fingerprints, because it
+ defeats MiTM-attacks.
diff --git a/src/fripost-postinst-udeb/finish-install.d/07fripost b/src/fripost-postinst-udeb/finish-install.d/07fripost
new file mode 100755
index 0000000..55d292b
--- /dev/null
+++ b/src/fripost-postinst-udeb/finish-install.d/07fripost
@@ -0,0 +1,275 @@
+#! /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>
+#
+# Licensed under the GNU GPL version 3 or higher.
+
+# TODO: blacklist firewire-related modules, to defeat DMA-based attacks.
+
+set -ue
+
+. /lib/fripost-partman/base.sh
+import=/cdrom/include
+
+# 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.
+ 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
+# 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
diff --git a/src/fripost-postinst-udeb/sshd_config b/src/fripost-postinst-udeb/sshd_config
new file mode 100644
index 0000000..e81b272
--- /dev/null
+++ b/src/fripost-postinst-udeb/sshd_config
@@ -0,0 +1,40 @@
+# What ports, IPs and protocols we listen for
+Port 22
+# Use these options to restrict which interfaces/protocols sshd will bind to
+#ListenAddress ::
+#ListenAddress 0.0.0.0
+Protocol 2
+# HostKeys for protocol version 2
+HostKey /etc/ssh/ssh_host_rsa_key
+#Privilege Separation is turned on for security
+UsePrivilegeSeparation yes
+
+# Logging
+SyslogFacility AUTH
+LogLevel INFO
+
+# Authentication:
+LoginGraceTime 120
+PermitRootLogin no
+AllowGroups ssh
+StrictModes yes
+
+PubkeyAuthentication yes
+#AuthorizedKeysFile %h/.ssh/authorized_keys
+
+# Change to yes to enable challenge-response passwords (beware issues with
+# some PAM modules and threads)
+ChallengeResponseAuthentication no
+
+# Change to no to disable tunnelled clear text passwords
+PasswordAuthentication no
+
+X11Forwarding no
+PrintMotd no
+PrintLastLog yes
+TCPKeepAlive yes
+
+# Allow client to pass locale environment variables
+AcceptEnv LANG LC_*
+
+Subsystem sftp /usr/lib/openssh/sftp-server
diff --git a/src/getname.sh b/src/getname.sh
new file mode 100755
index 0000000..f9ed5ec
--- /dev/null
+++ b/src/getname.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+# Usage:
+# getname.sh
+# Returns the list of all known .udeb files.
+# getname.sh [name]
+# Returns the canonical name of a package name.
+
+set -ue
+
+if [ $# -gt 0 ]; then
+ name="${1#src/}"
+ case "$1" in
+ src/*-udeb/*) name="${name%%/*}";;
+ *-udeb);;
+ *) name="${name%.udeb}"; name="${name%%_*}-udeb";;
+ esac
+ echo $name
+else
+ for dir in src/*-udeb/; do
+ if [ -r "$dir/debian/files" ]; then
+ echo src/$(cut -d' ' -f1 "$dir/debian/files")
+ else
+ sed -nr 's@^(\S+) \(([0-9.]+)\).*@src/\1_\2_all.udeb@p' "$dir/debian/changelog"
+ fi
+ done
+fi
+
diff --git a/virtualenv/virt b/virtualenv/virt
new file mode 100755
index 0000000..46c56dc
--- /dev/null
+++ b/virtualenv/virt
@@ -0,0 +1,133 @@
+#!/bin/sh
+#
+# Define and install a libvirt domain
+#
+# Copyright 2013 Guilhem Moulin <guilhem@fripost.org>
+#
+# Licensed under the GNU GPL version 3 or higher.
+#
+
+set -ue
+root=$(dirname "$0")
+
+help() {
+ cat >&2 <<-EOF
+ Usage:
+ $0 install <libvirt domain> [<QEMU image>]
+ Install the given domain, using the given image (created if
+ necessary) as a disk.
+ $0 view <libvirt domain>
+ Open a connection to a running domain using the Spice protocol
+ EOF
+ exit 1
+}
+
+get_XML_attribute() {
+ local domain="$1" object="$2" attribute="$3"
+
+ /usr/bin/virsh dumpxml "$domain" \
+ | /usr/bin/xmlstarlet sel -t -m /domain/"$object" -v @"$attribute"
+}
+
+doesExist() {
+ /usr/bin/virsh -r list --all --name | grep -qxF "$1"
+}
+isActive() {
+ /usr/bin/virsh -r list --name | grep -qxF "$1"
+}
+
+install() {
+ [ $# -eq 1 -o $# -eq 2 ] || help
+ local name=$1
+ local disk=${2:-$root/images/${name}.qcow2}
+
+ local darch version=$(sed -n 's/^VERSION\s*=\s*//p' $root/../preseed/Makefile)
+ case "${ARCH:=$(/bin/uname -m)}" in
+ i386|i686) darch=i386;;
+ x86_64) darch=amd64;;
+ *) darch=$ARCH;;
+ esac
+ local cdrom="$root/../preseed/dist/$darch/debian-$version-$darch-netinst-preseeded.iso"
+
+ if doesExist "$name"; then
+ echo "Error: Domain $name already exists. If you want to replace the domain, run" >&2
+ echo >&2
+ isActive "$name" && echo " virsh destroy $name" >&2
+ echo " virsh undefine $name" >&2
+ exit 1
+ fi
+ if ! [ -f "$cdrom" -a -r "$cdrom" ]; then
+ cat >&2 <<- EOF
+ Error: '$cdrom' does not exist or is not readable.
+ To create the preseeded image, run
+
+ cd $root/../preseed
+ ARCH=$darch make iso-preseed
+ EOF
+ exit 1
+ fi
+
+ grep -q '^kvm\s' /proc/modules || echo 'WARN: KVM not available!' >&2
+
+ if ! [ -r "$disk" -a -r "$disk" ]; then
+ local size=12G
+ echo "Creating (sparse) $size disk image '$disk'" >&2
+ /usr/bin/qemu-img create -f "${disk##*.}" \
+ -o size="$size",preallocation=metadata "$disk"
+ fi
+
+ # TODO: the bus should be chosen at random among sata,ide,scsi,usb
+ # TODO: test EFI: http://www.linux-kvm.org/page/OVMF
+ /usr/bin/virt-install -q \
+ --name "$name" \
+ --arch "$ARCH" \
+ --ram 128 \
+ --cdrom "$cdrom" \
+ --disk "$disk",cache=writeback,bus=sata \
+ --network network=default \
+ --graphics spice
+
+ cat >&2 <<- EOF
+ Domain '$name' has been created. As you can see in
+
+ virsh list
+
+ it should now be up and running. To open a graphical console, run
+
+ $0 view $name
+ EOF
+}
+
+view(){
+ [ $# -eq 1 ] || help
+ local domain="$1"
+
+ if ! doesExist "$domain"; then
+ cat >&2 <<- EOF
+ Error: Domain $domain does not exist. To create it, run
+
+ ./virt install $domain
+ EOF
+ exit 1
+ elif ! isActive "$domain"; then
+ echo "Error: Domain $domain is not active" >&2
+ exit 1
+ fi
+
+ local type=$(get_XML_attribute "$domain" devices/graphics type)
+ local port=$(get_XML_attribute "$domain" devices/graphics port) || true
+
+ if [ "$type" != spice -o -z "$port" ]; then
+ echo "Error: Could not find a valid Spice server on domain '$domain'." >&2
+ exit 1
+ fi
+ /usr/bin/spicec -h 127.0.0.1 -p $port
+}
+
+command="${1:-}"
+shift;
+
+case "$command" in
+ install|view) $command "$@";;
+ *) help
+esac