aboutsummaryrefslogtreecommitdiffstats
path: root/src/fripost-postinst-udeb/finish-install.d/07fripost
blob: 9483eab090de7d26dbb3a4eb6051073ad87bcc4f (plain)
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
276
277
278
279
280
281
282
283
284
285
286
#!/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

# 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