#!/bin/bash
# Let the user who asked use hotseat-inputd: add their uid to
# /etc/hotseat/inputd.allow. Installed by the .deb as
# /usr/lib/hotseat/hotseat-input-setup and run by the Hotseat app through
#   pkexec /usr/lib/hotseat/hotseat-input-setup
# which asks for an admin password in a dialog (the polkit action
# io.github.muspelheim.hotseat.input-setup) and sets PKEXEC_UID to the uid of
# the user who ran pkexec. In a console, over SSH included, where pkexec's
# text agent has no logind session to answer for ("No session for cookie"),
#   sudo /usr/lib/hotseat/hotseat-input-setup
# does the same with sudo's SUDO_UID. That uid, exactly, is added; nothing
# else is changed but the socket being enabled and started, and an allow
# file the service would not trust being made one it does. Run again, it
# changes nothing.

set -euo pipefail
umask 022

ALLOW_DIR=/etc/hotseat
ALLOW=/etc/hotseat/inputd.allow

die() {
    printf 'hotseat-input-setup: %s\n' "$*" >&2
    exit 1
}

warn() {
    printf 'hotseat-input-setup: %s\n' "$*" >&2
}

[ "$(id -u)" = 0 ] || die "run it as root, from your own account: sudo $0 (or pkexec $0)"
# The user who asked: pkexec's, else sudo's.
uid="${PKEXEC_UID:-${SUDO_UID:-}}"
case "$uid" in
    '' | *[!0-9]*) die "no PKEXEC_UID or SUDO_UID: run it from your own account with sudo $0" ;;
esac
[ "$uid" != 0 ] || die "hotseat never runs as root: run it from your own account"
name="$(getent passwd "$uid" | cut -d: -f1)" || name=""
[ -n "$name" ] || die "there is no user with uid $uid"

# The service trusts the file only when root owns it and its folder and
# nobody else can write either (bins/hotseat-inputd/src/allow.rs). install
# also puts right the owner and mode of a folder that is there already.
install -d -m 0755 -o root -g root "$ALLOW_DIR"

# Whether a file lists the uid as the service reads it: a line that is the
# uid alone once a # comment and the blanks around it are taken away. A line
# such as "1000 1001" lists nobody, for the service as for this.
listed() {
    awk -v uid="$uid" '
        { sub(/#.*/, ""); gsub(/^[[:space:]]+|[[:space:]]+$/, "") }
        $0 == uid { found = 1 }
        END { exit !found }
    ' "$1"
}

# What is there now. Its uids are kept only when nobody but root could have
# written them: a regular file, not a link, owned by root, that nobody else
# can write. Anyone who could write it otherwise could have listed
# themselves, so such a file is written anew, with this uid alone. The file
# is left as it is only when it is exactly as this writes it.
keep=0
if [ -L "$ALLOW" ]; then
    warn "$ALLOW is a link, not a file root wrote; it is written anew, and anyone it listed must run this again"
elif [ -e "$ALLOW" ] && [ ! -f "$ALLOW" ]; then
    die "$ALLOW is not a file: remove it, then run this again"
elif [ -f "$ALLOW" ]; then
    read -r owner group mode < <(stat -c '%u %g %a' -- "$ALLOW")
    if [ "$owner" = 0 ] && [ $((8#$mode & 8#022)) = 0 ]; then
        if [ "$group" = 0 ] && [ "$mode" = 644 ] && listed "$ALLOW"; then
            printf '%s (uid %s) may use hotseat-inputd already\n' "$name" "$uid"
            keep=as-is
        else
            keep=1
        fi
    else
        warn "$ALLOW could be changed by others than root (owner uid $owner, mode $mode); it is written anew, and anyone it listed must run this again"
    fi
fi

if [ "$keep" != as-is ]; then
    # Written beside the file and renamed over it, so the service never
    # reads half a file, and a link is replaced, not followed.
    tmp="$(mktemp "$ALLOW_DIR/.inputd.allow.XXXXXX")"
    trap 'rm -f "$tmp"' EXIT
    if [ "$keep" = 1 ]; then
        cat -- "$ALLOW" >"$tmp"
        # A last line with no line break would run into the new one.
        if [ -s "$tmp" ] && [ -n "$(tail -c 1 "$tmp")" ]; then
            printf '\n' >>"$tmp"
        fi
    else
        printf '%s\n' \
            "# The uids hotseat-inputd serves, one per line. Written by" \
            "# hotseat-input-setup; only root may change it." >"$tmp"
    fi
    if listed "$tmp"; then
        said="may use hotseat-inputd already; the file is root's again, mode 0644"
    else
        printf '%s # %s\n' "$uid" "$name" >>"$tmp"
        said="may now use hotseat-inputd"
    fi
    chown root:root "$tmp"
    chmod 0644 "$tmp"
    sync -- "$tmp" 2>/dev/null || true
    mv -fT -- "$tmp" "$ALLOW"
    trap - EXIT
    printf '%s (uid %s) %s\n' "$name" "$uid" "$said"
fi

if [ -d /run/systemd/system ]; then
    systemctl enable --now hotseat-inputd.socket
fi
