Files
Programming-Contests/files/lockdown/contest-restrictions
T
2026-10-15 20:44:05 -03:00

134 lines
4.9 KiB
Bash

#!/bin/bash
# Turns the contest restrictions off and on, for maintenance. Root only, so
# it is used through sudo from the administrator account (icpc).
#
# sudo contest-restrictions status
# sudo contest-restrictions report [SINCE] (refused attempts, default: today)
# sudo contest-restrictions off [all|firewall|usb|network]
# sudo contest-restrictions on [all|firewall|usb|network]
#
# firewall firewall, web proxy, DNS filter (/disable_firewall.sh, /enable_firewall.sh)
# usb USBGuard, USB disks and phones for the team account
# network network settings (Wi-Fi, hotspot, ...) for the team account
#
# "off" stays in effect after a reboot, until "on".
set -u
DISABLED=/etc/contest-restrictions/disabled
USB_FILES="/etc/polkit-1/rules.d/10-acpc-no-removable-media.rules /etc/udev/rules.d/72-acpc-no-phone-access.rules"
NETWORK_FILES="/etc/polkit-1/rules.d/10-acpc-no-network-changes.rules"
usage() {
sed -n '2,14p' "$0" | sed 's/^# \{0,1\}//'
exit 2
}
[ "$(id -u)" -eq 0 ] || { echo "Run it with sudo, from the administrator account." >&2; exit 1; }
mkdir -p "$DISABLED"
chmod 700 /etc/contest-restrictions
# Moves rule files out of the way (off) or back (on)
move_rules() {
action=$1
shift
for f in "$@"; do
if [ "$action" = off ] && [ -f "$f" ]; then
mv "$f" "$DISABLED/"
elif [ "$action" = on ] && [ -f "$DISABLED/$(basename "$f")" ]; then
mv "$DISABLED/$(basename "$f")" "$f"
fi
done
}
firewall() {
if [ "$1" = off ]; then
/disable_firewall.sh
else
/enable_firewall.sh
/refresh_rules.sh
fi
}
usb() {
if [ "$1" = off ]; then
systemctl disable --now usbguard.service
# USBGuard leaves the controllers refusing new devices when it stops
for f in /sys/bus/usb/devices/usb*/authorized_default; do
[ -e "$f" ] && echo 1 > "$f"
done
move_rules off $USB_FILES
udevadm control --reload
echo "USB devices allowed (unplug and plug again a device refused before)."
echo "USB disks and phones can be used from the team account."
else
# Removable media mounted while the restriction was off
findmnt -rno TARGET | grep '^/run/media/' | while read -r m; do
umount "$m" && echo "Unmounted $m"
done
move_rules on $USB_FILES
udevadm control --reload
systemctl enable --now usbguard.service
echo "USB restrictions on. The devices plugged in right now stay allowed until they are unplugged."
fi
}
network() {
if [ "$1" = off ]; then
move_rules off $NETWORK_FILES
echo "The team account can change the network settings."
else
move_rules on $NETWORK_FILES
echo "Network settings restricted to the administrators."
fi
}
state() {
if [ "$1" = yes ]; then echo "on"; else echo "OFF"; fi
}
status() {
fw=no; systemctl is-active --quiet firewall.service && fw=yes
us=no; systemctl is-active --quiet usbguard.service && [ -f /etc/polkit-1/rules.d/10-acpc-no-removable-media.rules ] && us=yes
nw=no; [ -f /etc/polkit-1/rules.d/10-acpc-no-network-changes.rules ] && nw=yes
echo "firewall $(state $fw)"
echo "usb $(state $us)"
echo "network $(state $nw)"
}
# What the machine refused: web sites, DNS names, USB devices
report() {
since=${1:-today}
echo "== Web sites refused by the proxy (since $since)"
journalctl -t contest_proxy --since "$since" --no-pager -o cat 2>/dev/null \
| awk '$3 != "200" || $4 == "-" {print $2}' | sort | uniq -c | sort -rn | head -40
echo
echo "== DNS names refused by the filter"
# Names that Firefox, VS Code, the IDEs and Kattis pages look up on their
# own in the background
background='(^|\.)(mozilla\.(com|org|net)|firefox-portal-detection\.com|googleapis\.com|gvt1\.com|microsoft\.com|vscode-cdn\.net|vscode-unpkg\.net|exp-tas\.com|openh264\.org|ipv4only\.arpa|sentry\.io|cloudflare-dns\.com|jetbrains\.com|ubuntu\.com|canonical\.com|snapcraft\.io)$'
names=$(journalctl -u contest-dns --since "$since" --no-pager -o cat 2>/dev/null \
| sed -n 's/^config \(.*\) is NXDOMAIN$/\1/p')
printf '%s\n' "$names" | grep -v -E "$background" | grep . | sort | uniq -c | sort -rn | head -40
echo " ($(printf '%s\n' "$names" | grep -c -E "$background") lookups by Firefox, VS Code and the IDEs in the background, not listed)"
echo
echo "== USB devices rejected"
journalctl -u usbguard --since "$since" --no-pager -o short 2>/dev/null \
| grep "target.new='reject'" \
| sed -E 's/^([A-Za-z]+ +[0-9]+ [0-9:]+).* name "([^"]*)".*/\1 \2/' | tail -20
}
case "${1:-}" in
status) status ;;
report) report "${2:-today}" ;;
on|off)
what=${2:-all}
case "$what" in
all) firewall "$1"; usb "$1"; network "$1" ;;
firewall|usb|network) "$what" "$1" ;;
*) usage ;;
esac
echo
status
;;
*) usage ;;
esac