From 968d09e362c7a58a08cefb68ca0628d642fe711f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Sch=C3=A4r?= Date: Thu, 9 May 2024 22:45:53 +0200 Subject: [PATCH] Initial commit --- .gitignore | 5 + LICENSE.txt | 15 + contestops/assign-user.sh | 20 + contestops/backup-create.sh | 25 + contestops/config-hosts | 9 + contestops/config-nftables.conf | 48 ++ contestops/configure-machines.sh | 22 + contestops/contest-lock.json | 5 + contestops/contestants.csv | 2 + contestops/create-certs.sh | 60 +++ contestops/hostlist | 3 + contestops/local-epfl.ssh_config | 202 +++++++++ contestops/local.ssh_config | 17 + contestops/readme.md | 184 ++++++++ contestops/set-display-scale.py | 37 ++ os/build.py | 213 +++++++++ os/config-example/config.toml | 6 + os/config-example/contestant_authorized_keys | 1 + os/config-example/installer-inventory.txt | 2 + .../inventory-hostname/debian/changelog | 5 + .../inventory-hostname/debian/control | 12 + .../debian/inventory-hostname.postinst | 43 ++ .../debian/inventory-hostname.templates | 15 + .../inventory-hostname/debian/rules | 3 + .../hooks/live/2010-contestant.hook.chroot | 30 ++ .../etc/dconf/db/local.d/00-disable-automount | 3 + .../etc/dconf/db/local.d/00-disable-idle | 3 + .../db/local.d/00-disable-screensaver-lock | 3 + .../etc/dconf/db/local.d/00-disable-suspend | 4 + .../etc/dconf/db/local.d/00-disallow-updates | 5 + .../db/local.d/00-gnome-shell-extensions | 2 + .../etc/dconf/db/local.d/00-lock-screen | 3 + .../etc/firefox/policies/policies.json | 23 + .../etc/polkit-1/rules.d/50-lockdown.rules | 17 + .../etc/ssh/sshd_config.d/sshd.conf | 2 + .../etc/systemd/system/live-config.service | 14 + .../systemd/timesyncd.conf.d/ntp-server.conf | 2 + .../usr/local/bin/install-client-cert | 49 ++ .../includes.chroot/usr/local/bin/live-config | 36 ++ .../usr/local/bin/reboot-interactive | 16 + .../usr/share/chromium/initial_bookmarks.html | 10 + .../contest-lock@soi.ch/extension.js | 428 ++++++++++++++++++ .../contest-lock@soi.ch/metadata.json | 8 + .../contest-lock@soi.ch/stylesheet-always.css | 24 + .../user-indicator@soi.ch/extension.js | 39 ++ .../user-indicator@soi.ch/metadata.json | 8 + .../user-indicator@soi.ch/stylesheet.css | 4 + .../package-lists/contestant.list.chroot | 12 + .../archives/sublime-text.key.chroot | 62 +++ .../archives/sublime-text.list.chroot | 1 + .../participant/archives/vscode.key.chroot | 19 + .../participant/archives/vscode.list.chroot | 1 + .../bootloaders/grub-pc/config.cfg | 31 ++ .../bootloaders/syslinux_common/splash.svg | 33 ++ .../hooks/live/2000-participant.hook.chroot | 47 ++ .../etc/dconf/db/local.d/00-background | 5 + .../etc/dconf/db/local.d/00-favorite-apps | 2 + .../etc/dconf/db/local.d/00-input-sources | 5 + .../includes.chroot/etc/dconf/profile/user | 2 + .../participant/includes.chroot/etc/motd | 0 .../share/backgrounds/wallpaper-soi-dark.svg | 14 + .../local/share/backgrounds/wallpaper-soi.svg | 14 + .../package-lists/live.list.chroot | 3 + .../package-lists/participant.list.chroot | 41 ++ .../preseed/participant.cfg.chroot | 1 + .../archives/fasttrack.list.chroot | 2 + .../debian-installer/udeb_exclude | 1 + .../live/2010-training-installer.hook.chroot | 7 + .../hooks/live/2010-training.hook.binary | 5 + .../etc/dconf/db/gdm.d/00-login-screen | 2 + .../includes.chroot/etc/dconf/profile/gdm | 3 + .../polkit-1/rules.d/50-network-system.rules | 9 + .../usr/local/bin/install-config | 17 + .../local/share/images/login-screen-logo.svg | 18 + .../local/share/target-sources/debian.sources | 11 + .../usr/share/pam-configs/noauth | 6 + .../includes.installer/bin/mountmedia | 6 + .../includes.installer/preseed.cfg | 28 ++ .../package-lists/live.list.chroot | 3 + .../training-installer.list.chroot | 16 + .../hooks/live/2010-training-live.hook.chroot | 6 + .../db/local.d/00-disable-screensaver-lock | 3 + .../etc/dconf/db/local.d/00-disallow-updates | 5 + .../etc/systemd/system/live-config.service | 14 + .../includes.chroot/usr/local/bin/live-config | 44 ++ .../package-lists/training-live.list.chroot | 4 + os/readme.md | 128 ++++++ readme.md | 5 + 88 files changed, 2323 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE.txt create mode 100755 contestops/assign-user.sh create mode 100755 contestops/backup-create.sh create mode 100644 contestops/config-hosts create mode 100644 contestops/config-nftables.conf create mode 100755 contestops/configure-machines.sh create mode 100644 contestops/contest-lock.json create mode 100644 contestops/contestants.csv create mode 100755 contestops/create-certs.sh create mode 100644 contestops/hostlist create mode 100644 contestops/local-epfl.ssh_config create mode 100644 contestops/local.ssh_config create mode 100644 contestops/readme.md create mode 100644 contestops/set-display-scale.py create mode 100755 os/build.py create mode 100644 os/config-example/config.toml create mode 100644 os/config-example/contestant_authorized_keys create mode 100644 os/config-example/installer-inventory.txt create mode 100644 os/installer-udeb/inventory-hostname/debian/changelog create mode 100644 os/installer-udeb/inventory-hostname/debian/control create mode 100644 os/installer-udeb/inventory-hostname/debian/inventory-hostname.postinst create mode 100644 os/installer-udeb/inventory-hostname/debian/inventory-hostname.templates create mode 100755 os/installer-udeb/inventory-hostname/debian/rules create mode 100755 os/layers/contestant/hooks/live/2010-contestant.hook.chroot create mode 100644 os/layers/contestant/includes.chroot/etc/dconf/db/local.d/00-disable-automount create mode 100644 os/layers/contestant/includes.chroot/etc/dconf/db/local.d/00-disable-idle create mode 100644 os/layers/contestant/includes.chroot/etc/dconf/db/local.d/00-disable-screensaver-lock create mode 100644 os/layers/contestant/includes.chroot/etc/dconf/db/local.d/00-disable-suspend create mode 100644 os/layers/contestant/includes.chroot/etc/dconf/db/local.d/00-disallow-updates create mode 100644 os/layers/contestant/includes.chroot/etc/dconf/db/local.d/00-gnome-shell-extensions create mode 100644 os/layers/contestant/includes.chroot/etc/dconf/db/local.d/00-lock-screen create mode 100644 os/layers/contestant/includes.chroot/etc/firefox/policies/policies.json create mode 100644 os/layers/contestant/includes.chroot/etc/polkit-1/rules.d/50-lockdown.rules create mode 100644 os/layers/contestant/includes.chroot/etc/ssh/sshd_config.d/sshd.conf create mode 100644 os/layers/contestant/includes.chroot/etc/systemd/system/live-config.service create mode 100644 os/layers/contestant/includes.chroot/etc/systemd/timesyncd.conf.d/ntp-server.conf create mode 100755 os/layers/contestant/includes.chroot/usr/local/bin/install-client-cert create mode 100755 os/layers/contestant/includes.chroot/usr/local/bin/live-config create mode 100755 os/layers/contestant/includes.chroot/usr/local/bin/reboot-interactive create mode 100644 os/layers/contestant/includes.chroot/usr/share/chromium/initial_bookmarks.html create mode 100644 os/layers/contestant/includes.chroot/usr/share/gnome-shell/extensions/contest-lock@soi.ch/extension.js create mode 100644 os/layers/contestant/includes.chroot/usr/share/gnome-shell/extensions/contest-lock@soi.ch/metadata.json create mode 100644 os/layers/contestant/includes.chroot/usr/share/gnome-shell/extensions/contest-lock@soi.ch/stylesheet-always.css create mode 100644 os/layers/contestant/includes.chroot/usr/share/gnome-shell/extensions/user-indicator@soi.ch/extension.js create mode 100644 os/layers/contestant/includes.chroot/usr/share/gnome-shell/extensions/user-indicator@soi.ch/metadata.json create mode 100644 os/layers/contestant/includes.chroot/usr/share/gnome-shell/extensions/user-indicator@soi.ch/stylesheet.css create mode 100644 os/layers/contestant/package-lists/contestant.list.chroot create mode 100644 os/layers/participant/archives/sublime-text.key.chroot create mode 100644 os/layers/participant/archives/sublime-text.list.chroot create mode 100644 os/layers/participant/archives/vscode.key.chroot create mode 100644 os/layers/participant/archives/vscode.list.chroot create mode 100644 os/layers/participant/bootloaders/grub-pc/config.cfg create mode 100644 os/layers/participant/bootloaders/syslinux_common/splash.svg create mode 100755 os/layers/participant/hooks/live/2000-participant.hook.chroot create mode 100644 os/layers/participant/includes.chroot/etc/dconf/db/local.d/00-background create mode 100644 os/layers/participant/includes.chroot/etc/dconf/db/local.d/00-favorite-apps create mode 100644 os/layers/participant/includes.chroot/etc/dconf/db/local.d/00-input-sources create mode 100644 os/layers/participant/includes.chroot/etc/dconf/profile/user create mode 100644 os/layers/participant/includes.chroot/etc/motd create mode 100644 os/layers/participant/includes.chroot/usr/local/share/backgrounds/wallpaper-soi-dark.svg create mode 100644 os/layers/participant/includes.chroot/usr/local/share/backgrounds/wallpaper-soi.svg create mode 100644 os/layers/participant/package-lists/live.list.chroot create mode 100644 os/layers/participant/package-lists/participant.list.chroot create mode 100644 os/layers/participant/preseed/participant.cfg.chroot create mode 100644 os/layers/training-installer/archives/fasttrack.list.chroot create mode 100644 os/layers/training-installer/debian-installer/udeb_exclude create mode 100644 os/layers/training-installer/hooks/live/2010-training-installer.hook.chroot create mode 100644 os/layers/training-installer/hooks/live/2010-training.hook.binary create mode 100644 os/layers/training-installer/includes.chroot/etc/dconf/db/gdm.d/00-login-screen create mode 100644 os/layers/training-installer/includes.chroot/etc/dconf/profile/gdm create mode 100644 os/layers/training-installer/includes.chroot/etc/polkit-1/rules.d/50-network-system.rules create mode 100755 os/layers/training-installer/includes.chroot/usr/local/bin/install-config create mode 100644 os/layers/training-installer/includes.chroot/usr/local/share/images/login-screen-logo.svg create mode 100644 os/layers/training-installer/includes.chroot/usr/local/share/target-sources/debian.sources create mode 100644 os/layers/training-installer/includes.chroot/usr/share/pam-configs/noauth create mode 100644 os/layers/training-installer/includes.installer/bin/mountmedia create mode 100644 os/layers/training-installer/includes.installer/preseed.cfg create mode 100644 os/layers/training-installer/package-lists/live.list.chroot create mode 100644 os/layers/training-installer/package-lists/training-installer.list.chroot create mode 100644 os/layers/training-live/hooks/live/2010-training-live.hook.chroot create mode 100644 os/layers/training-live/includes.chroot/etc/dconf/db/local.d/00-disable-screensaver-lock create mode 100644 os/layers/training-live/includes.chroot/etc/dconf/db/local.d/00-disallow-updates create mode 100644 os/layers/training-live/includes.chroot/etc/systemd/system/live-config.service create mode 100755 os/layers/training-live/includes.chroot/usr/local/bin/live-config create mode 100644 os/layers/training-live/package-lists/training-live.list.chroot create mode 100644 os/readme.md create mode 100644 readme.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8ac91c5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/os/config/ +/osbuild/ + +/contestops/certs/ +/contestops/local.known_hosts diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..1630324 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,15 @@ +The Gnome Shell extensions, which can be found under the path +/os/layers/contestant/includes.chroot/usr/share/gnome-shell/extensions, +are distributed under the terms of the GNU General Public License, version 2 or later. +See https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/main/COPYING for the license text. + +The rest of the repository is distributed under the MIT license, see below. + +The MIT License (MIT) +Copyright © 2024 Jan Schär + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/contestops/assign-user.sh b/contestops/assign-user.sh new file mode 100755 index 0000000..f2a5477 --- /dev/null +++ b/contestops/assign-user.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +machinename="$1" +username="$2" + +machineusername=contestant + +userline=$(grep "^$username;" contestants.csv) +if [ $? -ne 0 ]; then + echo "User $username not found" + exit 1 +fi +fullname=$(echo "$userline" | cut "-d;" -f2) + +# Set real name of machine user +ssh -F local.ssh_config "$machinename" chfn --full-name "\"$fullname\"" $machineusername + +# Install client certificate +scp -F local.ssh_config "certs/$username.p12" "$machinename:/home/$machineusername/clientcert.p12" +ssh -F local.ssh_config "$machinename" install-client-cert $machineusername diff --git a/contestops/backup-create.sh b/contestops/backup-create.sh new file mode 100755 index 0000000..fae7e3b --- /dev/null +++ b/contestops/backup-create.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +sleep_secs=120 + +do_backup() { + for host in $(cat hostlist); do + echo $host + target=backups/$host/$(date --iso-8601=seconds) + mkdir -p $target + rsync -e "ssh -F local.ssh_config" --recursive --links --perms --times --verbose --prune-empty-dirs --exclude ".*" --exclude "/snap" --exclude "Screenshot from *" --max-size 200K $host:/home/contestant/ $target + done +} + +if [ "$1" == timer ]; then + while true; do + do_backup + echo + echo "Finished, next backup in $sleep_secs seconds." + echo + echo + sleep $sleep_secs + done +else + do_backup +fi diff --git a/contestops/config-hosts b/contestops/config-hosts new file mode 100644 index 0000000..45a644f --- /dev/null +++ b/contestops/config-hosts @@ -0,0 +1,9 @@ +127.0.0.1 localhost +::1 localhost ip6-localhost ip6-loopback +fe00::0 ip6-localnet +ff00::0 ip6-mcastprefix +ff02::1 ip6-allnodes +ff02::2 ip6-allrouters + +89.58.34.6 contest.soi.ch +2a03:4000:64:8::1 contest.soi.ch diff --git a/contestops/config-nftables.conf b/contestops/config-nftables.conf new file mode 100644 index 0000000..be765ad --- /dev/null +++ b/contestops/config-nftables.conf @@ -0,0 +1,48 @@ +#!/usr/sbin/nft -f + +flush ruleset + +table inet filter { + chain input { + type filter hook input priority 0; + + ct state invalid drop + ct state { established, related } accept + + # Accept loopback + iif lo accept + + # Accept ICMP + ip protocol icmp accept + ip6 nexthdr icmpv6 accept + + # Accept incoming connections to these ports + tcp dport { ssh } accept + + reject + } + chain forward { + type filter hook forward priority 0; + reject + } + chain output { + type filter hook output priority 0; + + ct state invalid drop + ct state { established, related } accept + + # Accept loopback + oif lo accept + + # Accept outgoing connections to these addresses + ip daddr { 89.58.34.6 } tcp dport { https } accept + ip daddr { 89.58.34.6 } udp dport { ntp } accept + ip6 daddr { 2a03:4000:64:8::1 } tcp dport { https } accept + ip6 daddr { 2a03:4000:64:8::1 } udp dport { ntp } accept + + # Accept any connections by root user + #meta skuid root accept + + reject + } +} diff --git a/contestops/configure-machines.sh b/contestops/configure-machines.sh new file mode 100755 index 0000000..470ec37 --- /dev/null +++ b/contestops/configure-machines.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +set -ex + +# Disable WiFi. +parallel-ssh -x "-F local.ssh_config" -h hostlist nmcli radio wifi off + +# Create hosts file so we don't need DNS. +parallel-scp -x "-F local.ssh_config" -h hostlist ./config-hosts /etc/hosts + +# Configure firewall. +parallel-scp -x "-F local.ssh_config" -h hostlist ./config-nftables.conf /etc/nftables.conf +parallel-ssh -x "-F local.ssh_config" -h hostlist systemctl enable nftables.service +# For some unknown reason nft gets stuck the first time it is run. +parallel-ssh -x "-F local.ssh_config" -h hostlist --par 30 systemctl start nftables.service + +# Uncomment these lines if machines have 4K displays. This scales display to 2x. +# parallel-scp -x "-F local.ssh_config" -h hostlist ./set-display-scale.py /usr/local/bin/set-display-scale.py +# parallel-ssh -x "-F local.ssh_config" -h hostlist 'DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$(id -u contestant)/bus" runuser -u contestant -- python3 /usr/local/bin/set-display-scale.py' + +# Configure contest lock screen. +parallel-scp -x "-F local.ssh_config" -h hostlist ./contest-lock.json /etc/contest-lock.json diff --git a/contestops/contest-lock.json b/contestops/contest-lock.json new file mode 100644 index 0000000..60d38b4 --- /dev/null +++ b/contestops/contest-lock.json @@ -0,0 +1,5 @@ +{ + "title": "SOI Finals 2024 · Day 1", + "message": "", + "startTime": "2024-01-01T10:00:00+01:00" +} diff --git a/contestops/contestants.csv b/contestops/contestants.csv new file mode 100644 index 0000000..094e38a --- /dev/null +++ b/contestops/contestants.csv @@ -0,0 +1,2 @@ +stofl;Mouse Stofl +binna1;Mouse Binna diff --git a/contestops/create-certs.sh b/contestops/create-certs.sh new file mode 100755 index 0000000..d245c51 --- /dev/null +++ b/contestops/create-certs.sh @@ -0,0 +1,60 @@ +#!/usr/bin/env bash +# install cfssl + +set -e + +usernames=$(cat contestants.csv | cut "-d;" -f1) + +mkdir -p certs +cd certs + +cat < ca.json +{ + "CN": "SOI Contest Root CA", + "key": { + "algo": "rsa", + "size": 2048 + } +} + +EOF + +if [ ! -f ca.pem ]; then + cfssl gencert -initca ca.json | cfssljson -bare ca +fi + +cat <client-config.json +{ + "signing": { + "default": { + "expiry": "438000h" + }, + "profiles": { + "client": { + "usages": ["signing", "key encipherment", "digital signature", "client auth"], + "expiry": "438000h" + } + } + } +} + +EOF + +for username in $usernames; do + +cat <client-csr-$username.json +{ + "CN": "$username", + "key": { + "algo": "rsa", + "size": 2048 + } +} + +EOF + +cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=client-config.json -profile=client client-csr-$username.json | cfssljson --bare $username-cert + +openssl pkcs12 -export -in $username-cert.pem -inkey $username-cert-key.pem -out $username.p12 -passout pass: + +done diff --git a/contestops/hostlist b/contestops/hostlist new file mode 100644 index 0000000..3298585 --- /dev/null +++ b/contestops/hostlist @@ -0,0 +1,3 @@ +contestant01 +contestant02 +contestant03 diff --git a/contestops/local-epfl.ssh_config b/contestops/local-epfl.ssh_config new file mode 100644 index 0000000..c76ac12 --- /dev/null +++ b/contestops/local-epfl.ssh_config @@ -0,0 +1,202 @@ +# ssh config for room INF3 at EPFL + +Host contestant01 + HostName 128.178.158.101 + +Host contestant02 + HostName 128.178.158.102 + +Host contestant03 + HostName 128.178.158.103 + +Host contestant04 + HostName 128.178.158.104 + +Host contestant05 + HostName 128.178.158.105 + +Host contestant06 + HostName 128.178.158.106 + +Host contestant07 + HostName 128.178.158.107 + +Host contestant08 + HostName 128.178.158.108 + +Host contestant09 + HostName 128.178.158.109 + +Host contestant10 + HostName 128.178.158.110 + +Host contestant11 + HostName 128.178.158.111 + +Host contestant12 + HostName 128.178.158.112 + +Host contestant13 + HostName 128.178.158.113 + +Host contestant14 + HostName 128.178.158.114 + +Host contestant15 + HostName 128.178.158.115 + +Host contestant16 + HostName 128.178.158.116 + +Host contestant17 + HostName 128.178.158.117 + +Host contestant18 + HostName 128.178.158.118 + +Host contestant19 + HostName 128.178.158.119 + +Host contestant20 + HostName 128.178.158.120 + +Host contestant21 + HostName 128.178.158.121 + +Host contestant22 + HostName 128.178.158.122 + +Host contestant23 + HostName 128.178.158.123 + +Host contestant24 + HostName 128.178.158.124 + +Host contestant25 + HostName 128.178.158.125 + +Host contestant26 + HostName 128.178.158.126 + +Host contestant27 + HostName 128.178.158.127 + +Host contestant28 + HostName 128.178.158.128 + +Host contestant29 + HostName 128.178.158.129 + +Host contestant30 + HostName 128.178.158.130 + +Host contestant31 + HostName 128.178.158.131 + +Host contestant32 + HostName 128.178.158.132 + +Host contestant33 + HostName 128.178.158.133 + +Host contestant34 + HostName 128.178.158.134 + +Host contestant35 + HostName 128.178.158.135 + +Host contestant36 + HostName 128.178.158.136 + +Host contestant37 + HostName 128.178.158.137 + +Host contestant38 + HostName 128.178.158.138 + +Host contestant39 + HostName 128.178.158.139 + +Host contestant40 + HostName 128.178.158.140 + +Host contestant41 + HostName 128.178.158.141 + +Host contestant42 + HostName 128.178.158.142 + +Host contestant43 + HostName 128.178.158.143 + +Host contestant44 + HostName 128.178.158.144 + +Host contestant45 + HostName 128.178.158.145 + +Host contestant46 + HostName 128.178.158.146 + +Host contestant47 + HostName 128.178.158.147 + +Host contestant48 + HostName 128.178.158.148 + +Host contestant49 + HostName 128.178.158.149 + +Host contestant50 + HostName 128.178.158.150 + +Host contestant51 + HostName 128.178.158.151 + +Host contestant52 + HostName 128.178.158.152 + +Host contestant53 + HostName 128.178.158.153 + +Host contestant54 + HostName 128.178.158.154 + +Host contestant55 + HostName 128.178.158.155 + +Host contestant56 + HostName 128.178.158.156 + +Host contestant57 + HostName 128.178.158.157 + +Host contestant58 + HostName 128.178.158.158 + +Host contestant59 + HostName 128.178.158.159 + +Host contestant60 + HostName 128.178.158.160 + +Host contestant61 + HostName 128.178.158.161 + +Host contestant62 + HostName 128.178.158.162 + +Host contestant63 + HostName 128.178.158.163 + +Host contestant64 + HostName 128.178.158.164 + +Host vm + HostName localhost + Port 2222 + +Host * + User root + UserKnownHostsFile ./local.known_hosts + HashKnownHosts no diff --git a/contestops/local.ssh_config b/contestops/local.ssh_config new file mode 100644 index 0000000..2b86604 --- /dev/null +++ b/contestops/local.ssh_config @@ -0,0 +1,17 @@ +Host contestant01 + HostName 10.42.0.101 + +Host contestant02 + HostName 10.42.0.102 + +Host contestant03 + HostName 10.42.0.103 + +Host vm + HostName localhost + Port 2222 + +Host * + User root + UserKnownHostsFile ./local.known_hosts + HashKnownHosts no diff --git a/contestops/readme.md b/contestops/readme.md new file mode 100644 index 0000000..a9e5623 --- /dev/null +++ b/contestops/readme.md @@ -0,0 +1,184 @@ +# Contest ops + +Here are instructions and various scripts and files for running contests. + +The setup consists of a machine for each contestant, a machine running the grader, and an admin machine. +All these should be connected through a network, preferably wired. +The grader can be a machine accessible over the internet or in the local network. + +## Grader setup + +Install an ntp server on the grader machine. +This ensures that the contestant machine clocks are synchronized with the grader clock. +If a firewall is enabled, you may need to open the NTP port. + +```bash +sudo apt install ntpsec +``` + +Configure the grader to accept client certificates. +The CA certificate (`certs/ca.pem`) is generated as part of the admin setup. + +## Contestant machine setup + +Obtain the contestant ISO, or build it yourself. + +Flash the ISO to an USB stick. +All data on the stick will be lost. +For example, with the Gnome Disks utility, select the USB stick, open the menu on the right of the title bar, and click "Restore Disk Image...". + +Boot the contestant machine from the USB stick. +Insert the stick and power on the machine. +Then repeatedly press a key to enter the boot menu (which key depends on the model, e.g. F12). +The boot menu may be password protected on machines in computer rooms; in that case you need to know the password. +The OS is loaded into RAM during boot, so you can remove the stick once the boot is finished and boot the next machine. + +## Network setup + +If there is not already an existing network, you need to set it up yourself. +Connect all contestant machines and the admin machine to a network switch with LAN cables. +If you use multiple switches, don't forget to also link the switches together. + +If the grader must be accessed over the internet, you can connect the admin machine to WiFi or USB tethering with a phone. +You can then share the internet with the local network. + +If you have Gnome, go to Network settings, click on the gear on the Ethernet connection, go to IPv4 tab, and select "Shared to other computers". + +If you have docker installed, this doesn't work yet, because docker blocks routing. +You can fix it by running the following commands. + +```bash +sudo iptables -I DOCKER-USER -i en+ -j ACCEPT +sudo iptables -I DOCKER-USER -o en+ -j ACCEPT +``` + +## Admin setup + +This guide assumes that the admin machine is running Debian, Ubuntu or similar. + +Invent a password for root on the machines. +Create a password hash for it with the following command. +Put the hash in the `contest_root_password` variable in `os/config/config.toml`. +This must be done before building the ISO. + +```bash +sudo apt install whois +mkpasswd +``` + +Install parallel-ssh. + +```bash +sudo apt install pssh +``` + +Edit `contestants.csv` and fill in the username and real name of each contestant. + +Run the script to create a CA and client certificates. + +```bash +sudo apt install golang-cfssl +./create-certs.sh +``` + +Edit `local.ssh_config` and create an entry with hostname and IP address for each contestant machine. +You can get the IP address by running `ip addr` in a terminal on the contestant machine. + +Edit `hostlist` and add the hostnames of all contestant machines. + +Get ssh host keys. +After rebooting machines, delete `local.known_hosts` and run this command again. + +```bash +parallel-ssh -x "-F local.ssh_config" -h hostlist -O StrictHostKeyChecking=accept-new true +``` + +Test time synchronization. + +```bash +parallel-ssh -x "-F local.ssh_config" -h hostlist -i date +``` + +Edit `config-hosts` and `config-nftables.conf` to fill in the correct IP addresses for the grader. +You can look these up with `host contest.soi.ch`. + +Edit `contest-lock.json` to fill in the title and start time of the contest. + +Apply the configuration to machines. +If the script gets stuck, press Ctrl+C and run it again. + +```bash +./configure-machines.sh +``` + +Assign users to machines. + +```bash +./assign-user.sh contestant01 stofl +./assign-user.sh contestant02 binna1 +``` + +Start periodic backup of contestant machines. + +```bash +./backup-create.sh timer +``` + +## Restore machine from backup + +Because machines run from RAM, they will lose all files after rebooting. +Therefore, backups are especially important. + +To restore a backup to a spare machine, use the following commands. +Prepare in advance by keeping the user to machine assignment nearby for reference, and +replacing `contestant03` in the commands below with the spare machine hostname. + +```bash +./assign-user.sh contestant03 +rsync -e "ssh -F local.ssh_config" -av --chown contestant:contestant backups/contestantxx/xxxx/ contestant03:/home/contestant/ +``` + +## Contest lock screen + +The contest lock screen is a gnome extension which can lock the screen and show a countdown until the contest starts. +The screen is unlocked when the contest starts. +The lock screen also displays the user name and a title. +It is configured in the file `/etc/contest-lock.json`. +It watches this file, and when it changes the new configuration is instantly applied. + +If there is an error in the config file, it will continue to use the old config and print a message. +To see the logs, run this on a contestant machine: + +```bash +journalctl -f -o cat /usr/bin/gnome-shell +``` + +An additional text can be shown with the `message` field. It can contain newlines (`\n`). + + +In case there is a problem with the contest lock screen and you can't fix it, the backup solution is to turn off `AutomaticLoginEnable` and set a password instead, that you announce when the contest starts. + +```bash +parallel-ssh -x "-F local.ssh_config" -h hostlist 'chpasswd <<< contestant:stofl' +``` + +**Development notes** + +Links: +- https://www.codeproject.com/Articles/5271677/How-to-Create-A-GNOME-Extension +- https://gjs.guide/ + +Regular lock screen (contest-lock is based on this): +- https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/main/js/ui/screenShield.js +- https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/main/js/ui/unlockDialog.js + +Developer commands: +- Open the gnome-shell developer tools: Press Alt+F2, enter `lg`. + +## Problems and solutions + +Here are solutions to recurring problems. + +**User indicator does not appear.** +Fixed by adding the gnome shell version from `gnome-shell --version` to the list of supported versions: `shell-version` in `os/layers/contestant/includes.chroot/usr/share/gnome-shell/extensions/user-indicator@soi.ch/metadata.json`. +The same applies for the contest-lock extension. diff --git a/contestops/set-display-scale.py b/contestops/set-display-scale.py new file mode 100644 index 0000000..9dff943 --- /dev/null +++ b/contestops/set-display-scale.py @@ -0,0 +1,37 @@ +#!/usr/bin/python3 + +# This script sets the display scale factor to 2, for use on 4K displays where everything is too small without scaling. + +import dbus + +new_scale = 2.0 + +# https://gitlab.gnome.org/GNOME/mutter/-/blob/main/data/dbus-interfaces/org.gnome.Mutter.DisplayConfig.xml +bus_name = "org.gnome.Mutter.DisplayConfig" +object_path = "/org/gnome/Mutter/DisplayConfig" + +session_bus = dbus.SessionBus() +display_config_object = session_bus.get_object(bus_name, object_path) +display_config_intf = dbus.Interface(display_config_object, dbus_interface=bus_name) + +serial, physical_monitors, logical_monitors, properties = display_config_intf.GetCurrentState() + +current_mode_id = {} +for ((connector, _, _, _), modes, monitor_properties) in physical_monitors: + for (mode_id, width, height, rate, preferred_scale, supported_scales, mode_properties) in modes: + if mode_properties.get("is-current", False): + current_mode_id[connector] = mode_id + +scaled_logical_monitors = [ + (layout_x, layout_y, new_scale, transform, primary, [ + (connector, current_mode_id[connector], {}) for (connector, _, _, _) in monitors + ]) + for (layout_x, layout_y, scale, transform, primary, monitors, monitor_properties) in logical_monitors +] + +apply_properties = {} +if "layout-mode" in properties and properties.get("supports-changing-layout-mode", False): + apply_properties["layout-mode"] = properties["layout-mode"] + +method = 1 # temporary +display_config_intf.ApplyMonitorsConfig(serial, method, scaled_logical_monitors, apply_properties) diff --git a/os/build.py b/os/build.py new file mode 100755 index 0000000..5d47da7 --- /dev/null +++ b/os/build.py @@ -0,0 +1,213 @@ +#!/bin/env python3 + +# Build a live ISO. +# Run this from an empty working directory, +# or a directory where you have run this before to reuse caches. + +import argparse +import subprocess +import pathlib +import tomllib +import hashlib +import datetime +import urllib.request + + +DISTRIBUTION = "bookworm" + +VARIANT_LABEL = { + "contestant": "contest", + "training-live": "live", + "training-installer": "install", +} + +VARIANT_BOOT_OPTIONS = { + "contestant": [ + dict(label="SOI contest", cmdline="boot=live toram"), + dict(label="SOI contest, run from drive", cmdline="boot=live"), + dict(label="SOI contest, fail-safe mode", cmdline="@LB_BOOTAPPEND_LIVE_FAILSAFE@"), + ], + "training-live": [ + dict(label="SOI live system, run from RAM", cmdline="boot=live toram"), + dict(label="SOI live system, run from drive", cmdline="boot=live"), + dict(label="SOI live system, fail-safe mode", cmdline="@LB_BOOTAPPEND_LIVE_FAILSAFE@"), + ], + "training-installer": [], +} + +VARIANT_EXTRA_LB_CONFIG = { + "training-installer": [ + "--debian-installer", "live", + # Linux headers are needed for VirtualBox DKMS. + "--linux-packages", "linux-image linux-headers", + ], +} + +VARIANT_EXTRA_BOOTSTRAP = { + # Fasttrack keyring is needed for VirtualBox. + "training-installer": ",fasttrack-archive-keyring", +} + +DOWNLOADS = [ + dict( + name="soi-header.tar.gz", + url="https://git.soi.ch/SOI/soi-header/archive/19ddcef24eb55bdb5ddb817c1d91bfa04c8cb8dd.tar.gz", + sha256="38042587982af4e9431aea461e5c345bde358bcc79f0a0eadcf5b3ed77aeb8ab", + ), + # From https://soi.ch/wiki/soi-codeblocks/#install-the-soi-project-template + dict( + name="soi_template_codeblocks_ubuntu.zip", + url="https://soi.ch/media/files/soi_template_codeblocks_ubuntu_RzdvSho.zip", + sha256="3f4cae26bbb0cbdfd4cf9f94bfce14988e395f847948d9b349c12d0b980386e9", + ), +] + +def run(args, check=True, **kwargs): + print(f"> {' '.join(args)}") + subprocess.run(args, check=check, **kwargs) + +def edit_file(filename, fn): + with open(filename) as f: + content = f.read() + content = fn(content) + with open(filename, "w") as f: + f.write(content) + +def sha256sum(filename): + with open(filename, "rb", buffering=0) as f: + return hashlib.file_digest(f, "sha256").hexdigest() + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument( + "variant", + choices=["contestant", "training-live", "training-installer"], + help="Variant to build.", + ) + args = parser.parse_args() + + script_dir = pathlib.Path(__file__).parent.resolve() + chroot_includes = pathlib.Path("config/includes.chroot") + + with open(script_dir / "config/config.toml", "rb") as f: + config = tomllib.load(f) + + # Remove files generated by previous build, but keep cache. + run("lb clean".split()) + run("rm -rf .build config udeb-build".split()) + + # Download files. + run("mkdir -p downloads".split()) + for download in DOWNLOADS: + filename = f'downloads/{download["name"]}' + try: + if sha256sum(filename) == download["sha256"]: + continue + except FileNotFoundError: + pass + print(f'> Downloading {download["url"]}') + urllib.request.urlretrieve(download["url"], filename) + if sha256sum(filename) != download["sha256"]: + raise Exception(f"Downloaded file {filename} has wrong hash.") + + # Create base configuration directory. + run( + [ + "lb", "config", + "--clean", + "--ignore-system-defaults", + "--mode", "debian", + "--distribution", DISTRIBUTION, + "--archive-areas", "main contrib non-free non-free-firmware", + "--firmware-chroot", "false", + "--firmware-binary", "false", + "--apt-recommends", "false", + # isc-dhcp-client and ifupdown are obsoleted by network-manager, + # but they still have Priority: important. + # We need ca-certificates for fetching https packages repos. + "--debootstrap-options", "--exclude=isc-dhcp-client,isc-dhcp-common,ifupdown --include=ca-certificates" + + VARIANT_EXTRA_BOOTSTRAP.get(args.variant, ""), + "--loadlin", "false", + "--iso-volume", f"SOI {VARIANT_LABEL[args.variant]} @ISOVOLUME_TS@", + "--bootappend-live", "boot=live toram", + ] + + VARIANT_EXTRA_LB_CONFIG.get(args.variant, []) + ) + + # Add our own configuration on top. + run(["cp", "-rT", f"{script_dir}/layers/participant", "config"]) + run(["cp", "-rT", f"{script_dir}/layers/{args.variant}", "config"]) + + if args.variant == "training-installer": + # Insert admin password into preseed. + edit_file("config/includes.installer/preseed.cfg", + lambda s: s.replace("@install_admin_password@", config["install_admin_password"])) + + # Copy inventory file. + run("mkdir -p config/includes.binary/install".split()) + run(["cp", f"{script_dir}/config/installer-inventory.txt", "config/includes.binary/install/inventory.txt"]) + + # Insert build date in login screen logo. + edit_file("config/includes.chroot/usr/local/share/images/login-screen-logo.svg", + lambda s: s.replace("@date@", datetime.date.today().isoformat())) + + # Build and install custom udeb packages for installer. + run(["cp", "-rT", f"{script_dir}/installer-udeb", "udeb-build"]) + run("dpkg-buildpackage --build=all".split(), cwd="udeb-build/inventory-hostname") + run("mkdir -p config/packages.binary".split()) + run("cp udeb-build/inventory-hostname_0_all.udeb config/packages.binary/".split()) + + # Copy the source lists. The installer deletes everything in sources.list.d, + # so we need to copy them somewhere else and restore them after the install. + for listpath in pathlib.Path('config/archives').glob('*.list.chroot'): + run(["cp", str(listpath), f"config/includes.chroot/usr/local/share/target-sources/{listpath.name.removesuffix('.chroot')}"]) + elif args.variant == "contestant": + # Insert root password into hook script. + edit_file("config/hooks/live/2010-contestant.hook.chroot", + lambda s: s.replace("@contestant_root_password@", config["contestant_root_password"])) + + # Copy authorized_keys. + run("mkdir -p config/includes.chroot/root/.ssh".split()) + run(["cp", f"{script_dir}/config/contestant_authorized_keys", "config/includes.chroot/root/.ssh/authorized_keys"]) + + # Configure boot options. + grub_boot_options = '\n'.join( + f'menuentry "{option["label"]}" {{\n' + f' linux @KERNEL_LIVE@ {option["cmdline"]}\n' + f' initrd @INITRD_LIVE@\n' + f'}}\n' + for option in VARIANT_BOOT_OPTIONS[args.variant] + ) + with open("/usr/share/live/build/bootloaders/grub-pc/grub.cfg") as f: + grub_cfg = f.read() + grub_cfg = grub_cfg.replace("@LINUX_LIVE@", grub_boot_options) + with open("config/bootloaders/grub-pc/grub.cfg", "w") as f: + f.write(grub_cfg) + + syslinux_boot_options = ''.join( + f"label live-{i}\n" + f"\tmenu label {option['label']}\n" + + (f"\tmenu default\n" if i == 0 else "") + + f"\tlinux @LINUX@\n" + f"\tinitrd @INITRD@\n" + f"\tappend {option['cmdline'].replace('@LB_BOOTAPPEND_LIVE_FAILSAFE@', '@APPEND_LIVE_FAILSAFE@')}\n" + f"\n" + for i, option in enumerate(VARIANT_BOOT_OPTIONS[args.variant]) + ) + pathlib.Path("config/bootloaders/syslinux_common").mkdir(parents=True, exist_ok=True) + with open("config/bootloaders/syslinux_common/live.cfg.in", "w") as f: + f.write(syslinux_boot_options) + + # Install soi header. + (chroot_includes / "usr/local/include").mkdir(parents=True, exist_ok=True) + run(["tar", "--overwrite", "-xf", f"downloads/soi-header.tar.gz", "-C", f"{chroot_includes}/usr/local/include", "--strip-components=2", "soi-header/include/"]) + + # Install codeblocks template. + (chroot_includes / "usr/share/codeblocks/templates/wizard").mkdir(parents=True, exist_ok=True) + run(["unzip", "-o", f"downloads/soi_template_codeblocks_ubuntu.zip", "-d", f"{chroot_includes}/usr/share/codeblocks/templates/wizard/"]) + + # Start the build. + run("lb build".split()) + +if __name__ == "__main__": + main() diff --git a/os/config-example/config.toml b/os/config-example/config.toml new file mode 100644 index 0000000..ce0ff38 --- /dev/null +++ b/os/config-example/config.toml @@ -0,0 +1,6 @@ +# Example password: soi +# Create a hash with mkpasswd +install_admin_password = "$y$j9T$h5VhMd4KkdmbxdZD1gO0N/$1hvwZgO8pQw13Xd6jaNXbtkbqVOC4W/ia/KXOcCGYvB" + +# Example password: soi +contestant_root_password = "$y$j9T$h5VhMd4KkdmbxdZD1gO0N/$1hvwZgO8pQw13Xd6jaNXbtkbqVOC4W/ia/KXOcCGYvB" diff --git a/os/config-example/contestant_authorized_keys b/os/config-example/contestant_authorized_keys new file mode 100644 index 0000000..19cd57e --- /dev/null +++ b/os/config-example/contestant_authorized_keys @@ -0,0 +1 @@ +# Add your ssh authorized keys here diff --git a/os/config-example/installer-inventory.txt b/os/config-example/installer-inventory.txt new file mode 100644 index 0000000..06e1753 --- /dev/null +++ b/os/config-example/installer-inventory.txt @@ -0,0 +1,2 @@ +DEMO123 debian01 +SOME_SERIAL_NUMBER some-hostname diff --git a/os/installer-udeb/inventory-hostname/debian/changelog b/os/installer-udeb/inventory-hostname/debian/changelog new file mode 100644 index 0000000..b68ea47 --- /dev/null +++ b/os/installer-udeb/inventory-hostname/debian/changelog @@ -0,0 +1,5 @@ +inventory-hostname (0) UNRELEASED; urgency=low + + * Initial release. + + -- Jan Schär Fri, 02 Feb 2024 21:37:43 +0000 diff --git a/os/installer-udeb/inventory-hostname/debian/control b/os/installer-udeb/inventory-hostname/debian/control new file mode 100644 index 0000000..e56cba6 --- /dev/null +++ b/os/installer-udeb/inventory-hostname/debian/control @@ -0,0 +1,12 @@ +Source: inventory-hostname +Section: debian-installer +Priority: optional +Maintainer: Jan Schär +Build-Depends: debhelper-compat (= 13) + +Package: inventory-hostname +Package-Type: udeb +Architecture: all +Depends: ${misc:Depends} +XB-Installer-Menu-Item: 1650 +Description: Configure hostname using inventory list. diff --git a/os/installer-udeb/inventory-hostname/debian/inventory-hostname.postinst b/os/installer-udeb/inventory-hostname/debian/inventory-hostname.postinst new file mode 100644 index 0000000..6223256 --- /dev/null +++ b/os/installer-udeb/inventory-hostname/debian/inventory-hostname.postinst @@ -0,0 +1,43 @@ +#!/bin/sh -e +. /usr/share/debconf/confmodule +db_capb backup + +log() { + logger -t inventory-hostname "$@" +} + +INVENTORY_FILE=/cdrom/install/inventory.txt + +SERIAL=$(cat /sys/class/dmi/id/product_serial) + +if [ -z "$SERIAL" ]; then + log "Warning: No serial number found, skipping." + exit 0 +fi + +if [ ! -f "$INVENTORY_FILE" ]; then + log "Warning: No inventory file found at $INVENTORY_FILE, skipping." + exit 0 +fi + +SET_HOSTNAME=$(sed -n -e "s/^${SERIAL}\s\+\([0-9A-Za-z.-]\+\)\$/\1/p" "$INVENTORY_FILE") + +if [ -z "$SET_HOSTNAME" ]; then + db_subst inventory-hostname/get_hostname SERIAL "$SERIAL" + if ! db_input high inventory-hostname/get_hostname; then + # question not asked + exit 0 + fi + if ! db_go; then + exit 10 # back up + fi + + db_get inventory-hostname/get_hostname + SET_HOSTNAME="$RET" +elif [ "$(echo "$SET_HOSTNAME" | wc -l)" != "1" ]; then + log "Warning: Multiple inventory entries found for serial number $SERIAL, skipping." + exit 0 +fi + +db_set netcfg/get_hostname "$SET_HOSTNAME" +db_fset netcfg/get_hostname seen true diff --git a/os/installer-udeb/inventory-hostname/debian/inventory-hostname.templates b/os/installer-udeb/inventory-hostname/debian/inventory-hostname.templates new file mode 100644 index 0000000..61c05df --- /dev/null +++ b/os/installer-udeb/inventory-hostname/debian/inventory-hostname.templates @@ -0,0 +1,15 @@ +Template: debian-installer/inventory-hostname/title +Type: text +Description: Set hostname from inventory list + +Template: inventory-hostname/get_hostname +Type: string +Default: debian +Description: Hostname: + WARNING: The serial number of this machine was not found in the inventory list. + Are you sure you want to install on this machine? + If yes, you may want to add this machine to the inventory. + . + Serial number: ${SERIAL} + . + You can manually enter a hostname. diff --git a/os/installer-udeb/inventory-hostname/debian/rules b/os/installer-udeb/inventory-hostname/debian/rules new file mode 100755 index 0000000..78c7615 --- /dev/null +++ b/os/installer-udeb/inventory-hostname/debian/rules @@ -0,0 +1,3 @@ +#! /usr/bin/make -f +%: + dh $@ diff --git a/os/layers/contestant/hooks/live/2010-contestant.hook.chroot b/os/layers/contestant/hooks/live/2010-contestant.hook.chroot new file mode 100755 index 0000000..1e82426 --- /dev/null +++ b/os/layers/contestant/hooks/live/2010-contestant.hook.chroot @@ -0,0 +1,30 @@ +#!/bin/bash + +set -eu + +# Set root password. +chpasswd --encrypted <<< 'root:@contestant_root_password@' + +# Set chromium homepage. +sed -i 's|"homepage": ".*"|"homepage": "https://contest.soi.ch/"|' /etc/chromium/master_preferences +sed -i 's|"homepage_is_newtabpage": true,|"homepage_is_newtabpage": false,|' /etc/chromium/master_preferences + +# Disable Bluetooth. +systemctl disable bluetooth.service + +# Disable sleep. +systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target + +# Disable panels in gnome-control-center. +DISABLE_DESKTOP="dpkg-statoverride --force-statoverride-add --update --add root root 640" +$DISABLE_DESKTOP /usr/share/applications/gnome-bluetooth-panel.desktop +$DISABLE_DESKTOP /usr/share/applications/gnome-online-accounts-panel.desktop +$DISABLE_DESKTOP /usr/share/applications/gnome-sharing-panel.desktop + +# Enable the live system configuration script at boot. +systemctl enable live-config.service + +# Disable kexec-tools services. +# We want to load kexec manually, and execution of kexec is already done by systemd. +systemctl disable kexec-load.service +systemctl disable kexec.service diff --git a/os/layers/contestant/includes.chroot/etc/dconf/db/local.d/00-disable-automount b/os/layers/contestant/includes.chroot/etc/dconf/db/local.d/00-disable-automount new file mode 100644 index 0000000..aecaccd --- /dev/null +++ b/os/layers/contestant/includes.chroot/etc/dconf/db/local.d/00-disable-automount @@ -0,0 +1,3 @@ +# Disable automount +[org/gnome/desktop/media-handling] +automount = false diff --git a/os/layers/contestant/includes.chroot/etc/dconf/db/local.d/00-disable-idle b/os/layers/contestant/includes.chroot/etc/dconf/db/local.d/00-disable-idle new file mode 100644 index 0000000..50ea079 --- /dev/null +++ b/os/layers/contestant/includes.chroot/etc/dconf/db/local.d/00-disable-idle @@ -0,0 +1,3 @@ +# Disable blank screen +[org/gnome/desktop/session] +idle-delay = uint32 0 diff --git a/os/layers/contestant/includes.chroot/etc/dconf/db/local.d/00-disable-screensaver-lock b/os/layers/contestant/includes.chroot/etc/dconf/db/local.d/00-disable-screensaver-lock new file mode 100644 index 0000000..e71be0e --- /dev/null +++ b/os/layers/contestant/includes.chroot/etc/dconf/db/local.d/00-disable-screensaver-lock @@ -0,0 +1,3 @@ +# Disable lock on blank screen +[org/gnome/desktop/screensaver] +lock-enabled = false diff --git a/os/layers/contestant/includes.chroot/etc/dconf/db/local.d/00-disable-suspend b/os/layers/contestant/includes.chroot/etc/dconf/db/local.d/00-disable-suspend new file mode 100644 index 0000000..3486e18 --- /dev/null +++ b/os/layers/contestant/includes.chroot/etc/dconf/db/local.d/00-disable-suspend @@ -0,0 +1,4 @@ +# Disable suspend when inactive +[org/gnome/settings-daemon/plugins/power] +sleep-inactive-ac-type = 'nothing' +sleep-inactive-battery-type = 'nothing' diff --git a/os/layers/contestant/includes.chroot/etc/dconf/db/local.d/00-disallow-updates b/os/layers/contestant/includes.chroot/etc/dconf/db/local.d/00-disallow-updates new file mode 100644 index 0000000..556d13c --- /dev/null +++ b/os/layers/contestant/includes.chroot/etc/dconf/db/local.d/00-disallow-updates @@ -0,0 +1,5 @@ +# Disable "Updates available" notifications and auto updates. +# Updates which require reboot are useless on live systems, +# and other updates would be installed on each boot. +[org/gnome/software] +allow-updates = false diff --git a/os/layers/contestant/includes.chroot/etc/dconf/db/local.d/00-gnome-shell-extensions b/os/layers/contestant/includes.chroot/etc/dconf/db/local.d/00-gnome-shell-extensions new file mode 100644 index 0000000..afe0c96 --- /dev/null +++ b/os/layers/contestant/includes.chroot/etc/dconf/db/local.d/00-gnome-shell-extensions @@ -0,0 +1,2 @@ +[org/gnome/shell] +enabled-extensions = ['contest-lock@soi.ch', 'user-indicator@soi.ch'] diff --git a/os/layers/contestant/includes.chroot/etc/dconf/db/local.d/00-lock-screen b/os/layers/contestant/includes.chroot/etc/dconf/db/local.d/00-lock-screen new file mode 100644 index 0000000..3efe39e --- /dev/null +++ b/os/layers/contestant/includes.chroot/etc/dconf/db/local.d/00-lock-screen @@ -0,0 +1,3 @@ +# Disable locking the screen +[org/gnome/desktop/lockdown] +disable-lock-screen = true diff --git a/os/layers/contestant/includes.chroot/etc/firefox/policies/policies.json b/os/layers/contestant/includes.chroot/etc/firefox/policies/policies.json new file mode 100644 index 0000000..d66b74e --- /dev/null +++ b/os/layers/contestant/includes.chroot/etc/firefox/policies/policies.json @@ -0,0 +1,23 @@ +{ + "policies": { + "OverrideFirstRunPage": "", + "NoDefaultBookmarks": true, + "DisableProfileImport": true, + "Preferences": { + "datareporting.policy.dataSubmissionPolicyBypassNotification": true, + "security.default_personal_cert": "Select Automatically" + }, + "Homepage": { + "URL": "https://contest.soi.ch/", + "StartPage": "homepage" + }, + "DisplayBookmarksToolbar": true, + "Bookmarks": [ + { + "Title": "Contest", + "URL": "https://contest.soi.ch/", + "Placement": "toolbar" + } + ] + } +} diff --git a/os/layers/contestant/includes.chroot/etc/polkit-1/rules.d/50-lockdown.rules b/os/layers/contestant/includes.chroot/etc/polkit-1/rules.d/50-lockdown.rules new file mode 100644 index 0000000..16b8d86 --- /dev/null +++ b/os/layers/contestant/includes.chroot/etc/polkit-1/rules.d/50-lockdown.rules @@ -0,0 +1,17 @@ +// Show a root password prompt for these actions: +// - change network settings +// - hibernate +// - change package download proxy +// - mount removable storage, perform other disk operations + +polkit.addRule(function (action, subject) { + if ( + action.id.indexOf("org.freedesktop.ModemManager1.") === 0 || + action.id.indexOf("org.freedesktop.NetworkManager.") === 0 || + action.id === "org.freedesktop.login1.hibernate" || + action.id === "org.freedesktop.packagekit.system-network-proxy-configure" || + action.id.indexOf("org.freedesktop.udisks2.") === 0 + ) { + return polkit.Result.AUTH_ADMIN; + } +}); diff --git a/os/layers/contestant/includes.chroot/etc/ssh/sshd_config.d/sshd.conf b/os/layers/contestant/includes.chroot/etc/ssh/sshd_config.d/sshd.conf new file mode 100644 index 0000000..87f9b80 --- /dev/null +++ b/os/layers/contestant/includes.chroot/etc/ssh/sshd_config.d/sshd.conf @@ -0,0 +1,2 @@ +PasswordAuthentication no +AllowUsers root diff --git a/os/layers/contestant/includes.chroot/etc/systemd/system/live-config.service b/os/layers/contestant/includes.chroot/etc/systemd/system/live-config.service new file mode 100644 index 0000000..a8b5058 --- /dev/null +++ b/os/layers/contestant/includes.chroot/etc/systemd/system/live-config.service @@ -0,0 +1,14 @@ +[Unit] +Description=custom configuration of live system during boot. +Before=basic.target +After=local-fs.target systemd-tmpfiles-setup.service +DefaultDependencies=no +ConditionKernelCommandLine=boot=live + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/local/bin/live-config + +[Install] +WantedBy=basic.target diff --git a/os/layers/contestant/includes.chroot/etc/systemd/timesyncd.conf.d/ntp-server.conf b/os/layers/contestant/includes.chroot/etc/systemd/timesyncd.conf.d/ntp-server.conf new file mode 100644 index 0000000..76f5b3a --- /dev/null +++ b/os/layers/contestant/includes.chroot/etc/systemd/timesyncd.conf.d/ntp-server.conf @@ -0,0 +1,2 @@ +[Time] +NTP=contest.soi.ch diff --git a/os/layers/contestant/includes.chroot/usr/local/bin/install-client-cert b/os/layers/contestant/includes.chroot/usr/local/bin/install-client-cert new file mode 100755 index 0000000..9d7eece --- /dev/null +++ b/os/layers/contestant/includes.chroot/usr/local/bin/install-client-cert @@ -0,0 +1,49 @@ +#!/bin/bash + +# This tool installs the client certificate in Firefox and Chromium. + +username="$1" + +userhome="/home/$username" +certificate="$userhome/.config/clientcert.p12" + +runuser -u "$username" -- mkdir -p "$userhome/.config" +mv "$userhome/clientcert.p12" "$certificate" +chown "$username:$username" "$certificate" + +# Delete all Firefox data +rm -rf "$userhome/.mozilla/" + +# Create an empty profile +runuser -u "$username" -- mkdir -p "$userhome/.mozilla/firefox/main" + +# Tell Firefox to use this profile +cat > "$userhome/.mozilla/firefox/profiles.ini" < /etc/hostname +hostname "${LIVE_HOSTNAME}" + +# Create hosts file. +cat > /etc/hosts < + +Bookmarks +

Bookmarks

+

+

Bookmarks Bar

+

+

Contest +

+

diff --git a/os/layers/contestant/includes.chroot/usr/share/gnome-shell/extensions/contest-lock@soi.ch/extension.js b/os/layers/contestant/includes.chroot/usr/share/gnome-shell/extensions/contest-lock@soi.ch/extension.js new file mode 100644 index 0000000..d73ab3a --- /dev/null +++ b/os/layers/contestant/includes.chroot/usr/share/gnome-shell/extensions/contest-lock@soi.ch/extension.js @@ -0,0 +1,428 @@ +// Portions of this file are taken from GNOME Shell and adapted. +// Because of that, this gnome extension is distributed under +// the terms of the GNU General Public License, version 2 or later. + +const { + AccountsService, Atk, Clutter, Gio, + GLib, Graphene, Meta, Shell, St, +} = imports.gi; + +const Background = imports.ui.background; +const Layout = imports.ui.layout; +const Main = imports.ui.main; + +// half of the time for which a frame is displayed +const HALF_FRAME_TIME_MS = 8; + +const BLUR_BRIGHTNESS = 0.55; +const BLUR_SIGMA = 60; + +const POINTER_HIDE_TIMEOUT = 10 * GLib.USEC_PER_SEC; + +let actor; +let lockDialog; +let labelCountdown; +let labelTitle; +let labelMessage; +let labelUser; + +const bgManagers = []; +let backgroundGroup; + +let cursorTracker; +let motionId = 0; +let lastMotionTime = 0; +let pointerHidden = false; +let pointerHideId = 0; + +let user; + +let grab; +let countdownTimeoutId = 0; + +let configFile; +let configMonitor; +let config; +let startTime; + +let isExtensionEnabled = false; +let isActive = false; +let isShellReady = false; +let isActiveChanging = false; + +function extLog (msg) { + log(`[contest-lock] ${msg}`) +} + +function extLogError (msg) { + printerr(`[contest-lock] Error: ${msg}`); +} + +function loadConfig () { + configFile.load_contents_async(null, (obj, res) => { + // If there is a poblem with the config file, log an error and keep + // using the old config. + let newConfig; + try { + const [ok, bytes] = configFile.load_contents_finish(res); + // TextDecoder is used in upstream gnome-shell, but not yet + // supported in current Debian. + const contentStr = imports.byteArray.toString(bytes); + //const contentStr = new TextDecoder().decode(bytes); + newConfig = JSON.parse(contentStr); + } catch (err) { + logError(err, '[contest-lock] config file'); + return; + } + if (!(typeof newConfig === 'object' && newConfig != null)) { + extLogError('config file: invalid format'); + return; + } + if (typeof newConfig.title !== 'string') { + extLogError('config file: "title" must be a string'); + return; + } + if (typeof newConfig.message !== 'string') { + extLogError('config file: "message" must be a string'); + return; + } + if ( + typeof newConfig.startTime !== 'string' || + !/^\d{4,}-\d\d-\d\dT\d\d:\d\d:\d\d\+\d\d:\d\d$/.test(newConfig.startTime) + ) { + extLogError('config file: "startTime" must be a string with format 0000-00-00T00:00:00+00:00'); + return; + } + + extLog('Loaded new config.') + config = newConfig; + startTime = (new Date(newConfig.startTime)).getTime(); + + updateConfig(); + syncActive(); + }); +} + +function syncActive () { + if (isActiveChanging) return; + let beforeStart = false; + if (startTime != null) { + const now = new Date(); + const timeToStart = startTime - now.getTime() - HALF_FRAME_TIME_MS; + beforeStart = timeToStart > 0; + } + // ignore disable event when active + if (beforeStart && isShellReady && (isExtensionEnabled || isActive)) { + activate(); + } else { + deactivate(); + } +} + +function updateConfig () { + if (labelTitle != null) { + labelTitle.text = config.title; + } + if (labelMessage != null) { + labelMessage.text = config.message; + } +} + +function updateUser () { + if (labelUser != null) { + const realName = user.get_real_name(); + if (realName != null) labelUser.text = realName; + } +} + +function updateCountdown () { + countdownTimeoutId = 0; + const now = new Date(); + const nowTime = now.getTime() + HALF_FRAME_TIME_MS; + const timeToStart = startTime - nowTime; + const beforeStart = timeToStart > 0; + if (!beforeStart) { + deactivate(); + return GLib.SOURCE_REMOVE; + } + const allSecondsToStart = Math.floor(timeToStart / 1000); + const secondsToStart = allSecondsToStart % 60 + const allMinutesToStart = Math.floor(allSecondsToStart / 60); + const minutesToStart = allMinutesToStart % 60; + const hoursToStart = Math.floor(allMinutesToStart / 60); + + let hoursString = ''; + if (hoursToStart !== 0) hoursString = `${hoursToStart}∶`; + labelCountdown.text = hoursString + + minutesToStart.toString().padStart(2, '0') + '∶' + + secondsToStart.toString().padStart(2, '0'); + + // Force a redraw of the entire label widget. Without this, there sometimes + // appears a small artifact to the right of the text, which is only visible + // every other second. This seems to be a bug in the rendering engine itself. + labelCountdown.queue_redraw(); + + const nextUpdateTime = 1000 - nowTime % 1000 + countdownTimeoutId = GLib.timeout_add( + GLib.PRIORITY_HIGH, + nextUpdateTime, + updateCountdown + ); + GLib.Source.set_name_by_id(countdownTimeoutId, '[contest-lock] updateCountdown'); + + return GLib.SOURCE_REMOVE; +} + +function updateBackgrounds () { + if (!isActive) return; + while (bgManagers.length) bgManagers.pop().destroy(); + backgroundGroup.destroy_all_children(); + + for (let monitorIndex = 0; monitorIndex < Main.layoutManager.monitors.length; monitorIndex++) { + const monitor = Main.layoutManager.monitors[monitorIndex]; + const widget = new St.Widget({ + style_class: 'screen-shield-background', + x: monitor.x, + y: monitor.y, + width: monitor.width, + height: monitor.height, + effect: new Shell.BlurEffect({ + name: 'blur', + brightness: BLUR_BRIGHTNESS, + sigma: BLUR_SIGMA, + }), + }); + + const bgManager = new Background.BackgroundManager({ + container: widget, + monitorIndex, + controlPosition: false, + }); + + bgManagers.push(bgManager); + + backgroundGroup.add_child(widget); + } +} + +function pointerHideTimer () { + if (pointerHideId !== 0) { + GLib.source_remove(pointerHideId); + pointerHideId = 0; + } + if (!isActive) return GLib.SOURCE_REMOVE; + + const timeToHide = lastMotionTime + POINTER_HIDE_TIMEOUT - GLib.get_monotonic_time(); + if (timeToHide <= 0) { + cursorTracker.set_pointer_visible(false); + pointerHidden = true; + return GLib.SOURCE_REMOVE; + } + + pointerHideId = GLib.timeout_add( + GLib.PRIORITY_HIGH, + timeToHide / 1000 + 20, + pointerHideTimer + ); + GLib.Source.set_name_by_id(pointerHideId, '[contest-lock] pointerHide'); + + return GLib.SOURCE_REMOVE; +} + +function activate () { + if (isActive) return; + isActiveChanging = true; + isActive = true; + + grab = Main.pushModal(Main.uiGroup, { actionMode: Shell.ActionMode.LOCK_SCREEN }); + if (typeof grab === 'boolean') { // gnome 38 + if (!grab) { + grab = Main.pushModal(Main.uiGroup, { + options: Meta.ModalOptions.POINTER_ALREADY_GRABBED, + actionMode: Shell.ActionMode.LOCK_SCREEN + }); + } + if (!grab) { + extLogError('Failed to activate: Could not obtain keyboard grab.'); + return; + } + grab = Main.uiGroup; + } else if ((grab.get_seat_state() & Clutter.GrabState.KEYBOARD) === 0) { + Main.popModal(grab); + grab = null; + extLogError('Failed to activate: Could not obtain keyboard grab.'); + return; + } + + actor.show(); + + Main.sessionMode.pushMode('unlock-dialog'); + + backgroundGroup = new Clutter.Actor(); + + motionId = global.stage.connect('captured-event', (stage, event) => { + if (event.type() === Clutter.EventType.MOTION) { + lastMotionTime = GLib.get_monotonic_time(); + if (pointerHidden) { + cursorTracker.set_pointer_visible(true); + pointerHidden = false; + pointerHideTimer(); + } + } + + return Clutter.EVENT_PROPAGATE; + }); + cursorTracker.set_pointer_visible(false); + pointerHidden = true; + + labelCountdown = new St.Label({ + style_class: 'contest-lock-countdown', + x_align: Clutter.ActorAlign.CENTER, + }); + labelTitle = new St.Label({ + style_class: 'contest-lock-title', + x_align: Clutter.ActorAlign.CENTER, + }); + labelMessage = new St.Label({ + style_class: 'contest-lock-message', + x_align: Clutter.ActorAlign.CENTER, + }); + labelUser = new St.Label({ + style_class: 'contest-lock-user', + x_align: Clutter.ActorAlign.CENTER, + }); + + const stack = new St.BoxLayout({ + style_class: 'contest-lock-stack', + vertical: true, + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.CENTER, + y_align: Clutter.ActorAlign.CENTER, + }); + stack.add_child(labelUser); + stack.add_child(labelCountdown); + stack.add_child(labelTitle); + stack.add_child(labelMessage); + + const mainBox = new St.BoxLayout(); + mainBox.add_constraint(new Layout.MonitorConstraint({ primary: true })); + mainBox.add_child(stack); + + lockDialog = new St.Widget({ + name: 'contestLockDialog', + accessible_role: Atk.Role.WINDOW, + visible: false, + reactive: true, + can_focus: true, + x_expand: true, + y_expand: true, + pivot_point: new Graphene.Point({ x: 0.5, y: 0.5 }), + }); + lockDialog.add_child(backgroundGroup); + lockDialog.add_child(mainBox); + + updateConfig(); + updateUser(); + updateCountdown(); + updateBackgrounds(); + + // countdown may have just expired before we called updateCountdown + if (!isActive) return; + + actor.add_child(lockDialog); + lockDialog.show(); + + extLog('Activated.') + isActiveChanging = false; +} + +function deactivate () { + if (!isActive) return; + isActiveChanging = true; + isActive = false; + + if (Main.sessionMode.currentMode === 'unlock-dialog') { + Main.sessionMode.popMode('unlock-dialog'); + } + + Main.popModal(grab); + grab = null; + + if (countdownTimeoutId !== 0) { + GLib.source_remove(countdownTimeoutId); + countdownTimeoutId = 0; + } + + actor.hide(); + labelCountdown = null; + labelTitle = null; + labelMessage = null; + labelUser = null; + while (bgManagers.length) bgManagers.pop().destroy(); + lockDialog.destroy(); + lockDialog = null; + + if (motionId) { + global.stage.disconnect(motionId); + motionId = 0; + } + cursorTracker.set_pointer_visible(true); + + extLog('Deactivated.'); + isActiveChanging = false; +} + +function init (extension) { + actor = Main.layoutManager.screenShieldGroup; + + const userName = GLib.get_user_name(); + user = AccountsService.UserManager.get_default().get_user(userName); + if (!user) return; + + user.connect('notify::is-loaded', updateUser); + user.connect('changed', updateUser); + updateUser(); + + Main.layoutManager.connect('monitors-changed', updateBackgrounds); + + cursorTracker = Meta.CursorTracker.get_for_display(global.display); + + if (!Main.layoutManager._startingUp) { + isShellReady = true; + } else { + Main.layoutManager.connect('startup-complete', () => { + isShellReady = true; + syncActive(); + }); + } + + // TODO: When we drop compatibility with gnome <42, remove this code, + // rename the stylesheet back to stylesheet.css (so that it is loaded + // by the extension system) and add a session-modes property which + // includes unlock-dialog to metadata.json. + const theme = St.ThemeContext.get_for_stage(global.stage).get_theme(); + const stylesheetFile = extension.dir.get_child('stylesheet-always.css'); + theme.load_stylesheet(stylesheetFile); + + // TODO: When we drop compatibility with gnome <42, remove this code. + // gnome 38 has a bug that causes extensions to break when running + // `dconf update` while the screen is locked. + Main.extensionManager.reloadExtension = function () {}; + + configFile = Gio.File.new_for_path('/etc/contest-lock.json'); + configMonitor = configFile.monitor_file(Gio.FileMonitorFlags.NONE, null); + configMonitor.set_rate_limit(1000); + configMonitor.connect('changed', loadConfig); + loadConfig(); +} + +function enable () { + isExtensionEnabled = true; + syncActive(); +} + +function disable () { + isExtensionEnabled = false; + syncActive(); +} diff --git a/os/layers/contestant/includes.chroot/usr/share/gnome-shell/extensions/contest-lock@soi.ch/metadata.json b/os/layers/contestant/includes.chroot/usr/share/gnome-shell/extensions/contest-lock@soi.ch/metadata.json new file mode 100644 index 0000000..f2ec0c3 --- /dev/null +++ b/os/layers/contestant/includes.chroot/usr/share/gnome-shell/extensions/contest-lock@soi.ch/metadata.json @@ -0,0 +1,8 @@ +{ + "extension-id": "contest-lock", + "uuid": "contest-lock@soi.ch", + "name": "Contest lock screen", + "description": "A custom lock screen for contests.", + "shell-version": [ "3.38", "42", "43" ], + "url": "" +} diff --git a/os/layers/contestant/includes.chroot/usr/share/gnome-shell/extensions/contest-lock@soi.ch/stylesheet-always.css b/os/layers/contestant/includes.chroot/usr/share/gnome-shell/extensions/contest-lock@soi.ch/stylesheet-always.css new file mode 100644 index 0000000..49350b8 --- /dev/null +++ b/os/layers/contestant/includes.chroot/usr/share/gnome-shell/extensions/contest-lock@soi.ch/stylesheet-always.css @@ -0,0 +1,24 @@ +.contest-lock-stack { + color: white; + text-align: center; + spacing: 24px; +} + +.contest-lock-countdown { + font-size: 64pt; + font-weight: 300; + font-feature-settings: "tnum"; /* tabular figures */ +} + +.contest-lock-title { + font-size: 16pt; +} + +.contest-lock-user { + font-size: 20pt; +} + +.contest-lock-message { + padding-top: 24px; + font-size: 16pt; +} diff --git a/os/layers/contestant/includes.chroot/usr/share/gnome-shell/extensions/user-indicator@soi.ch/extension.js b/os/layers/contestant/includes.chroot/usr/share/gnome-shell/extensions/user-indicator@soi.ch/extension.js new file mode 100644 index 0000000..ae54cea --- /dev/null +++ b/os/layers/contestant/includes.chroot/usr/share/gnome-shell/extensions/user-indicator@soi.ch/extension.js @@ -0,0 +1,39 @@ +const { St, Clutter, GLib, Gio, AccountsService } = imports.gi; +const Main = imports.ui.main; + +let panelBin; +let userLabel; + +let user; + +function updateUser () { + const realName = user.get_real_name(); + if (realName != null) userLabel.text = realName; +} + +function init () { + panelBin = new St.Bin({ + style_class: 'panel-bin', + }); + userLabel = new St.Label({ + text: 'No user', + y_align: Clutter.ActorAlign.CENTER, + }); + panelBin.set_child(userLabel); + + const userName = GLib.get_user_name(); + user = AccountsService.UserManager.get_default().get_user(userName); + if (!user) return; + + user.connect('notify::is-loaded', updateUser); + user.connect('changed', updateUser); + updateUser(); +} + +function enable () { + Main.panel._rightBox.insert_child_at_index(panelBin, 0); +} + +function disable () { + Main.panel._rightBox.remove_child(panelBin); +} diff --git a/os/layers/contestant/includes.chroot/usr/share/gnome-shell/extensions/user-indicator@soi.ch/metadata.json b/os/layers/contestant/includes.chroot/usr/share/gnome-shell/extensions/user-indicator@soi.ch/metadata.json new file mode 100644 index 0000000..514c7c3 --- /dev/null +++ b/os/layers/contestant/includes.chroot/usr/share/gnome-shell/extensions/user-indicator@soi.ch/metadata.json @@ -0,0 +1,8 @@ +{ + "extension-id": "user-indicator", + "uuid": "user-indicator@soi.ch", + "name": "User indicator", + "description": "Shows the user's real name in the top bar.", + "shell-version": [ "3.38", "42", "43" ], + "url": "" +} diff --git a/os/layers/contestant/includes.chroot/usr/share/gnome-shell/extensions/user-indicator@soi.ch/stylesheet.css b/os/layers/contestant/includes.chroot/usr/share/gnome-shell/extensions/user-indicator@soi.ch/stylesheet.css new file mode 100644 index 0000000..008bcc8 --- /dev/null +++ b/os/layers/contestant/includes.chroot/usr/share/gnome-shell/extensions/user-indicator@soi.ch/stylesheet.css @@ -0,0 +1,4 @@ +.panel-bin { + padding-left: 12px; + padding-right: 12px; +} diff --git a/os/layers/contestant/package-lists/contestant.list.chroot b/os/layers/contestant/package-lists/contestant.list.chroot new file mode 100644 index 0000000..a64b790 --- /dev/null +++ b/os/layers/contestant/package-lists/contestant.list.chroot @@ -0,0 +1,12 @@ +# Remote access +openssh-server +rsync + +# Firewall +nftables + +# Reboot with kexec +kexec-tools + +# For importing client certificate +libnss3-tools diff --git a/os/layers/participant/archives/sublime-text.key.chroot b/os/layers/participant/archives/sublime-text.key.chroot new file mode 100644 index 0000000..3f11304 --- /dev/null +++ b/os/layers/participant/archives/sublime-text.key.chroot @@ -0,0 +1,62 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +McvDuGKIXk111Z3nrF4DeIIc/U6ICQ== +=CCk2 +-----END PGP PUBLIC KEY BLOCK----- diff --git a/os/layers/participant/archives/sublime-text.list.chroot b/os/layers/participant/archives/sublime-text.list.chroot new file mode 100644 index 0000000..ff49ad8 --- /dev/null +++ b/os/layers/participant/archives/sublime-text.list.chroot @@ -0,0 +1 @@ +deb http://download.sublimetext.com/ apt/stable/ diff --git a/os/layers/participant/archives/vscode.key.chroot b/os/layers/participant/archives/vscode.key.chroot new file mode 100644 index 0000000..6e319d4 --- /dev/null +++ b/os/layers/participant/archives/vscode.key.chroot @@ -0,0 +1,19 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.7 (GNU/Linux) + +mQENBFYxWIwBCADAKoZhZlJxGNGWzqV+1OG1xiQeoowKhssGAKvd+buXCGISZJwT +LXZqIcIiLP7pqdcZWtE9bSc7yBY2MalDp9Liu0KekywQ6VVX1T72NPf5Ev6x6DLV +7aVWsCzUAF+eb7DC9fPuFLEdxmOEYoPjzrQ7cCnSV4JQxAqhU4T6OjbvRazGl3ag +OeizPXmRljMtUUttHQZnRhtlzkmwIrUivbfFPD+fEoHJ1+uIdfOzZX8/oKHKLe2j +H632kvsNzJFlROVvGLYAk2WRcLu+RjjggixhwiB+Mu/A8Tf4V6b+YppS44q8EvVr +M+QvY7LNSOffSO6Slsy9oisGTdfE39nC7pVRABEBAAG0N01pY3Jvc29mdCAoUmVs +ZWFzZSBzaWduaW5nKSA8Z3Bnc2VjdXJpdHlAbWljcm9zb2Z0LmNvbT6JATUEEwEC +AB8FAlYxWIwCGwMGCwkIBwMCBBUCCAMDFgIBAh4BAheAAAoJEOs+lK2+EinPGpsH +/32vKy29Hg51H9dfFJMx0/a/F+5vKeCeVqimvyTM04C+XENNuSbYZ3eRPHGHFLqe +MNGxsfb7C7ZxEeW7J/vSzRgHxm7ZvESisUYRFq2sgkJ+HFERNrqfci45bdhmrUsy +7SWw9ybxdFOkuQoyKD3tBmiGfONQMlBaOMWdAsic965rvJsd5zYaZZFI1UwTkFXV +KJt3bp3Ngn1vEYXwijGTa+FXz6GLHueJwF0I7ug34DgUkAFvAs8Hacr2DRYxL5RJ +XdNgj4Jd2/g6T9InmWT0hASljur+dJnzNiNCkbn9KbX7J/qK1IbR8y560yRmFsU+ +NdCFTW7wY0Fb1fWJ+/KTsC4= +=J6gs +-----END PGP PUBLIC KEY BLOCK----- diff --git a/os/layers/participant/archives/vscode.list.chroot b/os/layers/participant/archives/vscode.list.chroot new file mode 100644 index 0000000..3c761df --- /dev/null +++ b/os/layers/participant/archives/vscode.list.chroot @@ -0,0 +1 @@ +deb http://packages.microsoft.com/repos/code stable main diff --git a/os/layers/participant/bootloaders/grub-pc/config.cfg b/os/layers/participant/bootloaders/grub-pc/config.cfg new file mode 100644 index 0000000..471d285 --- /dev/null +++ b/os/layers/participant/bootloaders/grub-pc/config.cfg @@ -0,0 +1,31 @@ +set timeout=5 + +# Everything below is copied from the default config. + +set default=0 + +if [ x$feature_default_font_path = xy ] ; then + font=unicode +else + font=$prefix/unicode.pf2 +fi + +# Copied from the netinst image +if loadfont $font ; then + set gfxmode=800x600 + set gfxpayload=keep + insmod efi_gop + insmod efi_uga + insmod video_bochs + insmod video_cirrus +else + set gfxmode=auto + insmod all_video +fi + +insmod gfxterm +insmod png + +source /boot/grub/theme.cfg + +terminal_output gfxterm diff --git a/os/layers/participant/bootloaders/syslinux_common/splash.svg b/os/layers/participant/bootloaders/syslinux_common/splash.svg new file mode 100644 index 0000000..43635fc --- /dev/null +++ b/os/layers/participant/bootloaders/syslinux_common/splash.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + @PROJECT@ @VERSION@ (@DISTRIBUTION@) + @ARCHITECTURE@ + Built: @YEAR@-@MONTH@-@DAY@ @HOUR@:@MINUTE@:@SECOND@ @TIMEZONE@ + linux: @LINUX_VERSIONS@ + + + diff --git a/os/layers/participant/hooks/live/2000-participant.hook.chroot b/os/layers/participant/hooks/live/2000-participant.hook.chroot new file mode 100755 index 0000000..1a45aa6 --- /dev/null +++ b/os/layers/participant/hooks/live/2000-participant.hook.chroot @@ -0,0 +1,47 @@ +#!/bin/bash + +set -eu + +# Update dconf database after having put files in /etc/dconf/. +dconf update + +# Configure timezone. +TIMEZONE=Europe/Zurich +echo "$TIMEZONE" > /etc/timezone +ln -sf /usr/share/zoneinfo/"$TIMEZONE" /etc/localtime + +# Install VS Code extensions. +VSCODE_EXTENSIONS="ms-python.python ms-vscode.cpptools swissolyinfo.soicode" +mkdir /etc/skel/.vscode +chown nobody:nogroup /etc/skel/.vscode +for ext in $VSCODE_EXTENSIONS; do + runuser -u nobody -- code --user-data-dir=/tmp/vsc.tmp \ + --extensions-dir=/etc/skel/.vscode/extensions \ + --install-extension="$ext" +done +chown -R root:root /etc/skel/.vscode +rm -rf /tmp/vsc.tmp + +# Enable codeblocks template. +sed -i 's|// project wizards|RegisterWizard(wizProject, _T("soi"), _T("A SOI task"), _T("Console"));|' /usr/share/codeblocks/templates/wizard/config.script + +# Add a default keyring to avoid a prompt to create one when launching Chromium. +mkdir -p /etc/skel/.local/share/keyrings/ +chmod og= /etc/skel/.local/share/keyrings/ +echo -n "Default_keyring" > /etc/skel/.local/share/keyrings/default +cat > /etc/skel/.local/share/keyrings/Default_keyring.keyring < +Swiss Olympiad in Informatics + + + + + + + + + + + + diff --git a/os/layers/participant/includes.chroot/usr/local/share/backgrounds/wallpaper-soi.svg b/os/layers/participant/includes.chroot/usr/local/share/backgrounds/wallpaper-soi.svg new file mode 100644 index 0000000..3738093 --- /dev/null +++ b/os/layers/participant/includes.chroot/usr/local/share/backgrounds/wallpaper-soi.svg @@ -0,0 +1,14 @@ + +Swiss Olympiad in Informatics + + + + + + + + + + + + diff --git a/os/layers/participant/package-lists/live.list.chroot b/os/layers/participant/package-lists/live.list.chroot new file mode 100644 index 0000000..a73fd32 --- /dev/null +++ b/os/layers/participant/package-lists/live.list.chroot @@ -0,0 +1,3 @@ +live-boot + +# This file overrides a default list to remove live-config. diff --git a/os/layers/participant/package-lists/participant.list.chroot b/os/layers/participant/package-lists/participant.list.chroot new file mode 100644 index 0000000..cac11fb --- /dev/null +++ b/os/layers/participant/package-lists/participant.list.chroot @@ -0,0 +1,41 @@ +# firmware +firmware-linux amd64-microcode intel-microcode +firmware-iwlwifi firmware-brcm80211 firmware-realtek + +# system +systemd-timesyncd +locales +zstd +wpasupplicant +wireless-regdb + +# desktop +gnome-core +xdg-user-dirs-gtk +network-manager-gnome +# needed for ejecting UBS sticks in nautilus +eject + +# shell utilities +htop unzip + +# software for participants +firefox-esr chromium-l10n +codeblocks emacs geany gedit joe kate kdevelop nano vim vim-gtk3 +gcc g++ gdb ddd valgrind python3 pypy3 +evince gnome-terminal konsole xterm byobu make cmake +nautilus-extension-gnome-terminal +file-roller +# for drawing on screenshots +drawing +# documentation +info manpages-dev gcc-doc gdb-doc +# from third-party repositories +sublime-text code +# requested by participants (gnome-tweaks can be used e.g. to change the function of Caps Lock key) +gnome-tweaks fonts-firacode + +# translations +manpages-de manpages-fr manpages-it +gcc-12-locales +firefox-esr-l10n-de firefox-esr-l10n-fr firefox-esr-l10n-it diff --git a/os/layers/participant/preseed/participant.cfg.chroot b/os/layers/participant/preseed/participant.cfg.chroot new file mode 100644 index 0000000..275218d --- /dev/null +++ b/os/layers/participant/preseed/participant.cfg.chroot @@ -0,0 +1 @@ +locales locales/locales_to_be_generated multiselect en_US.UTF-8 UTF-8, de_CH.UTF-8 UTF-8, fr_CH.UTF-8 UTF-8, it_CH.UTF-8 UTF-8 diff --git a/os/layers/training-installer/archives/fasttrack.list.chroot b/os/layers/training-installer/archives/fasttrack.list.chroot new file mode 100644 index 0000000..8bbe769 --- /dev/null +++ b/os/layers/training-installer/archives/fasttrack.list.chroot @@ -0,0 +1,2 @@ +# Fasttrack is needed for VirtualBox. +deb https://fasttrack.debian.net/debian-fasttrack/ @DISTRIBUTION@-fasttrack main contrib diff --git a/os/layers/training-installer/debian-installer/udeb_exclude b/os/layers/training-installer/debian-installer/udeb_exclude new file mode 100644 index 0000000..8f2315a --- /dev/null +++ b/os/layers/training-installer/debian-installer/udeb_exclude @@ -0,0 +1 @@ +ethdetect diff --git a/os/layers/training-installer/hooks/live/2010-training-installer.hook.chroot b/os/layers/training-installer/hooks/live/2010-training-installer.hook.chroot new file mode 100644 index 0000000..c98afce --- /dev/null +++ b/os/layers/training-installer/hooks/live/2010-training-installer.hook.chroot @@ -0,0 +1,7 @@ +#!/bin/bash + +set -eu + +# Install the noauth PAM profile. +groupadd noauth +pam-auth-update --enable noauth diff --git a/os/layers/training-installer/hooks/live/2010-training.hook.binary b/os/layers/training-installer/hooks/live/2010-training.hook.binary new file mode 100644 index 0000000..6be24d2 --- /dev/null +++ b/os/layers/training-installer/hooks/live/2010-training.hook.binary @@ -0,0 +1,5 @@ +#!/bin/bash + +set -eu + +echo "inventory-hostname" >> .disk/udeb_include diff --git a/os/layers/training-installer/includes.chroot/etc/dconf/db/gdm.d/00-login-screen b/os/layers/training-installer/includes.chroot/etc/dconf/db/gdm.d/00-login-screen new file mode 100644 index 0000000..81a1a10 --- /dev/null +++ b/os/layers/training-installer/includes.chroot/etc/dconf/db/gdm.d/00-login-screen @@ -0,0 +1,2 @@ +[org/gnome/login-screen] +logo = '/usr/local/share/images/login-screen-logo.svg' diff --git a/os/layers/training-installer/includes.chroot/etc/dconf/profile/gdm b/os/layers/training-installer/includes.chroot/etc/dconf/profile/gdm new file mode 100644 index 0000000..817afc5 --- /dev/null +++ b/os/layers/training-installer/includes.chroot/etc/dconf/profile/gdm @@ -0,0 +1,3 @@ +user-db:user +system-db:gdm +file-db:/usr/share/gdm/greeter-dconf-defaults diff --git a/os/layers/training-installer/includes.chroot/etc/polkit-1/rules.d/50-network-system.rules b/os/layers/training-installer/includes.chroot/etc/polkit-1/rules.d/50-network-system.rules new file mode 100644 index 0000000..02e4292 --- /dev/null +++ b/os/layers/training-installer/includes.chroot/etc/polkit-1/rules.d/50-network-system.rules @@ -0,0 +1,9 @@ +// Connecting to a WiFi in the gnome-shell quick settings prompts for an admin +// password without this rule. +// https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/7378 + +polkit.addRule(function (action, subject) { + if (action.id === "org.freedesktop.NetworkManager.settings.modify.system") { + return polkit.Result.YES; + } +}); diff --git a/os/layers/training-installer/includes.chroot/usr/local/bin/install-config b/os/layers/training-installer/includes.chroot/usr/local/bin/install-config new file mode 100755 index 0000000..39bfad6 --- /dev/null +++ b/os/layers/training-installer/includes.chroot/usr/local/bin/install-config @@ -0,0 +1,17 @@ +#!/bin/sh + +set -eu + +# Set up apt lists. +cp -rT /usr/local/share/target-sources /etc/apt/sources.list.d +rm /etc/apt/sources.list + +USERNAME=soi +USER_FULLNAME="SOI" +# Password: soi +USER_PASSWORD='$y$j9T$h5VhMd4KkdmbxdZD1gO0N/$1hvwZgO8pQw13Xd6jaNXbtkbqVOC4W/ia/KXOcCGYvB' + +# Create user. +adduser --disabled-password --gecos "$USER_FULLNAME" "$USERNAME" +usermod -p "$USER_PASSWORD" "$USERNAME" +adduser "$USERNAME" noauth diff --git a/os/layers/training-installer/includes.chroot/usr/local/share/images/login-screen-logo.svg b/os/layers/training-installer/includes.chroot/usr/local/share/images/login-screen-logo.svg new file mode 100644 index 0000000..3b0fbef --- /dev/null +++ b/os/layers/training-installer/includes.chroot/usr/local/share/images/login-screen-logo.svg @@ -0,0 +1,18 @@ + +Swiss Olympiad in Informatics + + + + + + + + + + + + This laptop is property of the Swiss Olympiad in Informatics. Contact: info@soi.ch + Dieser Laptop ist Eigentum der Schweizer Informatikolympiade. Kontakt: info@soi.ch + Software version: @date@ + + diff --git a/os/layers/training-installer/includes.chroot/usr/local/share/target-sources/debian.sources b/os/layers/training-installer/includes.chroot/usr/local/share/target-sources/debian.sources new file mode 100644 index 0000000..a7c1e88 --- /dev/null +++ b/os/layers/training-installer/includes.chroot/usr/local/share/target-sources/debian.sources @@ -0,0 +1,11 @@ +Types: deb deb-src +URIs: http://deb.debian.org/debian +Suites: bookworm bookworm-updates +Components: main contrib non-free non-free-firmware +Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg + +Types: deb deb-src +URIs: http://deb.debian.org/debian-security +Suites: bookworm-security +Components: main contrib non-free non-free-firmware +Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg diff --git a/os/layers/training-installer/includes.chroot/usr/share/pam-configs/noauth b/os/layers/training-installer/includes.chroot/usr/share/pam-configs/noauth new file mode 100644 index 0000000..279a3a7 --- /dev/null +++ b/os/layers/training-installer/includes.chroot/usr/share/pam-configs/noauth @@ -0,0 +1,6 @@ +Name: Accept noauth users without any authentication +Default: yes +Priority: 512 +Auth-Type: Primary +Auth: + [success=end default=ignore] pam_succeed_if.so user ingroup noauth diff --git a/os/layers/training-installer/includes.installer/bin/mountmedia b/os/layers/training-installer/includes.installer/bin/mountmedia new file mode 100644 index 0000000..0eb1d2c --- /dev/null +++ b/os/layers/training-installer/includes.installer/bin/mountmedia @@ -0,0 +1,6 @@ +#!/bin/sh + +# Disable mountmedia, because that can make the cdrom mount fail. +# Not sure why there are two conflicting mounting mechanisms in Debian Installer +# (mountmedia with /media and cdrom-detect with /cdrom). +exit 1 diff --git a/os/layers/training-installer/includes.installer/preseed.cfg b/os/layers/training-installer/includes.installer/preseed.cfg new file mode 100644 index 0000000..d21fb29 --- /dev/null +++ b/os/layers/training-installer/includes.installer/preseed.cfg @@ -0,0 +1,28 @@ +#_preseed_V1 + +d-i debian-installer/language string en +d-i debian-installer/country string CH +d-i debian-installer/locale string en_US.UTF-8 + +d-i keyboard-configuration/xkb-keymap select ch + +d-i hw-detect/load_firmware boolean false + +d-i netcfg/enable boolean false +d-i netcfg/get_domain string + +d-i passwd/root-login boolean false +d-i passwd/user-fullname string Admin +d-i passwd/username string superstofl +d-i passwd/user-password-crypted password @install_admin_password@ + +d-i partman-auto/method string regular +d-i partman-auto/init_automatically_partition select some_device +d-i partman-auto/choose_recipe select atomic +d-i partman/choose_partition select finish + +d-i apt-setup/use_mirror boolean false + +d-i grub-installer/only_debian boolean true + +d-i preseed/late_command string in-target /usr/local/bin/install-config diff --git a/os/layers/training-installer/package-lists/live.list.chroot b/os/layers/training-installer/package-lists/live.list.chroot new file mode 100644 index 0000000..aac01e3 --- /dev/null +++ b/os/layers/training-installer/package-lists/live.list.chroot @@ -0,0 +1,3 @@ +# This file overrides a default list to remove live-config. +# For the installer, we don't need any live packages, +# they would just be removed again by the installer. diff --git a/os/layers/training-installer/package-lists/training-installer.list.chroot b/os/layers/training-installer/package-lists/training-installer.list.chroot new file mode 100644 index 0000000..cd8d058 --- /dev/null +++ b/os/layers/training-installer/package-lists/training-installer.list.chroot @@ -0,0 +1,16 @@ +sudo + +# Make Secure Boot work +grub-efi-amd64-signed + +# Firmware updates through gnome-software +fwupd fwupd-signed + +# Low battery charge notifications, battery info +gnome-power-manager + +# Run virtual machines with Gnome Boxes +gnome-boxes qemu-system-x86 qemu-utils libvirt-daemon-system + +# Run virtual machines with VirtualBox +virtualbox-qt diff --git a/os/layers/training-live/hooks/live/2010-training-live.hook.chroot b/os/layers/training-live/hooks/live/2010-training-live.hook.chroot new file mode 100644 index 0000000..7398a8d --- /dev/null +++ b/os/layers/training-live/hooks/live/2010-training-live.hook.chroot @@ -0,0 +1,6 @@ +#!/bin/bash + +set -eu + +# Enable the live system configuration script at boot. +systemctl enable live-config.service diff --git a/os/layers/training-live/includes.chroot/etc/dconf/db/local.d/00-disable-screensaver-lock b/os/layers/training-live/includes.chroot/etc/dconf/db/local.d/00-disable-screensaver-lock new file mode 100644 index 0000000..e71be0e --- /dev/null +++ b/os/layers/training-live/includes.chroot/etc/dconf/db/local.d/00-disable-screensaver-lock @@ -0,0 +1,3 @@ +# Disable lock on blank screen +[org/gnome/desktop/screensaver] +lock-enabled = false diff --git a/os/layers/training-live/includes.chroot/etc/dconf/db/local.d/00-disallow-updates b/os/layers/training-live/includes.chroot/etc/dconf/db/local.d/00-disallow-updates new file mode 100644 index 0000000..556d13c --- /dev/null +++ b/os/layers/training-live/includes.chroot/etc/dconf/db/local.d/00-disallow-updates @@ -0,0 +1,5 @@ +# Disable "Updates available" notifications and auto updates. +# Updates which require reboot are useless on live systems, +# and other updates would be installed on each boot. +[org/gnome/software] +allow-updates = false diff --git a/os/layers/training-live/includes.chroot/etc/systemd/system/live-config.service b/os/layers/training-live/includes.chroot/etc/systemd/system/live-config.service new file mode 100644 index 0000000..a8b5058 --- /dev/null +++ b/os/layers/training-live/includes.chroot/etc/systemd/system/live-config.service @@ -0,0 +1,14 @@ +[Unit] +Description=custom configuration of live system during boot. +Before=basic.target +After=local-fs.target systemd-tmpfiles-setup.service +DefaultDependencies=no +ConditionKernelCommandLine=boot=live + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/local/bin/live-config + +[Install] +WantedBy=basic.target diff --git a/os/layers/training-live/includes.chroot/usr/local/bin/live-config b/os/layers/training-live/includes.chroot/usr/local/bin/live-config new file mode 100755 index 0000000..6ac7b39 --- /dev/null +++ b/os/layers/training-live/includes.chroot/usr/local/bin/live-config @@ -0,0 +1,44 @@ +#!/bin/bash + +set -eu + +LIVE_HOSTNAME=debian + +LIVE_USERNAME=soi +LIVE_USER_FULLNAME="SOI live" +# Password: soi +LIVE_USER_PASSWORD='$y$j9T$h5VhMd4KkdmbxdZD1gO0N/$1hvwZgO8pQw13Xd6jaNXbtkbqVOC4W/ia/KXOcCGYvB' + +# Set hostname. +echo "${LIVE_HOSTNAME}" > /etc/hostname +hostname "${LIVE_HOSTNAME}" + +# Create hosts file. +cat > /etc/hosts < /etc/sudoers.d/10_customize <