1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
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
|