#!/bin/sh # deprovision-kiosk.sh — remove the Vestibule kiosk session from this # machine (Linux). The inverse of provision-kiosk.sh, applied in reverse # order: # # 1. The vestibule-kiosk systemd unit (stop, disable, delete) # 2. /usr/local/bin/vestibule-kiosk-launch and /etc/vestibule # 3. Vestibule's merged policies.json everywhere it was deployed — # LibreWolf native/Flatpak, Firefox native (/etc/firefox), and the # kiosk-home locations for Firefox Flatpak/snap. Each directory is # reset to its pre-Vestibule baseline: the backed-up operator file # is reinstalled where one exists, Vestibule's generated file is # deleted where one does not. # 4. The usher Native Messaging manifests from the kiosk user's home # (all five locations: LibreWolf + Firefox, native + Flatpak + snap) # 5. The sandbox-visible XPI copies (Flatpak/snap flavors) # 6. Optionally: the kiosk account, /opt/vestibule, /usr/local/bin/usher # # The regular getty/console login is never modified, so removing the # unit is all it takes to return the machine to a stock boot. # # Exit codes: # 0 success # 2 not root / no systemd # 5 removal failure # # Usage: # sudo ./deprovision-kiosk.sh # keep account + /opt # sudo ./deprovision-kiosk.sh --remove-user --remove-opt --remove-usher # # POSIX sh — no bashisms. set -eu KIOSK_USER="vestibule-kiosk" LW_FLATPAK_APP="io.gitlab.librewolf-community" FF_FLATPAK_APP="org.mozilla.firefox" OPT_ROOT="/opt/vestibule" UNIT_DST="/etc/systemd/system/vestibule-kiosk.service" LAUNCH_DST="/usr/local/bin/vestibule-kiosk-launch" ENV_DIR="/etc/vestibule" USHER_DST="/usr/local/bin/usher" REMOVE_USER=0 REMOVE_OPT=0 REMOVE_USHER=0 ASSUME_YES=0 CHECK=0 usage() { cat <<'EOF' deprovision-kiosk.sh — remove the Vestibule kiosk session from this machine Options: --kiosk-user NAME Kiosk account name (default: vestibule-kiosk) --remove-user Also delete the kiosk account and its home directory --remove-opt Also delete /opt/vestibule (staged files, XPI, docs) --remove-usher Also delete /usr/local/bin/usher --yes Skip the confirmation prompt --check Show what would be removed; change nothing -h, --help This text EOF } die() { code="$1"; msg="$2" echo "" echo "ERROR: ${msg}" >&2 echo " exiting with code ${code}" >&2 exit "${code}" } info() { echo "$1"; } ok() { echo " [ok] $1"; } step() { echo ""; echo "==> $1"; } while [ $# -gt 0 ]; do case "$1" in --kiosk-user) KIOSK_USER="$2"; shift 2 ;; --remove-user) REMOVE_USER=1; shift ;; --remove-opt) REMOVE_OPT=1; shift ;; --remove-usher) REMOVE_USHER=1; shift ;; --yes|-y) ASSUME_YES=1; shift ;; --check) CHECK=1; shift ;; -h|--help) usage; exit 0 ;; *) usage >&2; die 5 "unknown option: $1" ;; esac done if [ ! -d /run/systemd/system ]; then die 2 "systemd is not the running init system" fi # ─── Discover current state ─────────────────────────────────────────── UNIT_ACTIVE=0 if systemctl is-active vestibule-kiosk.service >/dev/null 2>&1; then UNIT_ACTIVE=1 fi UNIT_ENABLED=0 if systemctl is-enabled vestibule-kiosk.service >/dev/null 2>&1; then UNIT_ENABLED=1 fi KIOSK_HOME="" if id -u "${KIOSK_USER}" >/dev/null 2>&1; then KIOSK_HOME=$(getent passwd "${KIOSK_USER}" | cut -d: -f6) fi step "Current state" info "unit : $(if [ -f "${UNIT_DST}" ]; then echo present; else echo absent; fi) (active: ${UNIT_ACTIVE}, enabled: ${UNIT_ENABLED})" info "launcher : $(if [ -x "${LAUNCH_DST}" ]; then echo present; else echo absent; fi)" info "kiosk.env : $(if [ -f "${ENV_DIR}/kiosk.env" ]; then echo present; else echo absent; fi)" info "kiosk account : $(if [ -n "${KIOSK_HOME}" ]; then echo "present (home: ${KIOSK_HOME})"; else echo absent; fi)" info "opt root : $(if [ -d "${OPT_ROOT}" ]; then echo present; else echo absent; fi)" if [ "${CHECK}" -eq 1 ]; then info "(check only — no changes made)" exit 0 fi [ "$(id -u)" -eq 0 ] || die 2 "must run as root (sudo)" if [ "${ASSUME_YES}" -eq 0 ]; then echo "" printf "Proceed with removal? [y/N] " read -r answer case "${answer}" in y|Y|yes|YES) ;; *) info "aborted"; exit 0 ;; esac fi # ─── 1. systemd unit ────────────────────────────────────────────────── step "Remove kiosk session" if [ -f "${UNIT_DST}" ]; then systemctl stop vestibule-kiosk.service 2>/dev/null || true systemctl disable vestibule-kiosk.service 2>/dev/null || true rm -f "${UNIT_DST}" systemctl daemon-reload ok "unit stopped, disabled, and removed" else info "unit already absent" fi # ─── 2. Launcher + env ──────────────────────────────────────────────── step "Remove launcher + session config" if [ -x "${LAUNCH_DST}" ]; then rm -f "${LAUNCH_DST}" ok "removed ${LAUNCH_DST}" fi if [ -d "${ENV_DIR}" ]; then rm -rf "${ENV_DIR}" ok "removed ${ENV_DIR}" fi # ─── 3. Policies ────────────────────────────────────────────────────── step "Reset browser policies to baseline" reset_policy_dir() { # Step-down, one decision per line: # absent directory -> nothing to do # baseline backup present -> reinstall it over Vestibule's merge # Vestibule-generated file -> delete it (no pre-Vestibule baseline) _dir="$1" if [ ! -d "${_dir}" ]; then return fi _dst="${_dir}/policies.json" _bak="${_dst}.vestibule-bak" if [ -f "${_bak}" ]; then mv "${_bak}" "${_dst}" ok "baseline policies.json reinstalled in ${_dir}" elif [ -f "${_dst}" ] && grep -q "vestibule@vestibule\.kiosk" "${_dst}" 2>/dev/null; then rm -f "${_dst}" ok "Vestibule-generated policies.json deleted in ${_dir} (no baseline on record)" fi } reset_policy_dir /usr/lib/librewolf/distribution reset_policy_dir /usr/share/librewolf/distribution reset_policy_dir /opt/librewolf/distribution reset_policy_dir "/var/lib/flatpak/app/${LW_FLATPAK_APP}/current/active/files/librewolf/distribution" reset_policy_dir /etc/firefox/policies if [ -n "${KIOSK_HOME}" ]; then reset_policy_dir "${KIOSK_HOME}/.var/app/${FF_FLATPAK_APP}/.mozilla/policies" reset_policy_dir "${KIOSK_HOME}/snap/firefox/common/.mozilla/policies" fi # ─── 4. Native Messaging manifests ──────────────────────────────────── step "Remove Native Messaging manifests" if [ -n "${KIOSK_HOME}" ]; then rm -f "${KIOSK_HOME}/.librewolf/native-messaging-hosts/com.vestibule.usher.json" rm -f "${KIOSK_HOME}/.mozilla/native-messaging-hosts/com.vestibule.usher.json" rm -f "${KIOSK_HOME}/.var/app/${LW_FLATPAK_APP}/.librewolf/native-messaging-hosts/com.vestibule.usher.json" rm -f "${KIOSK_HOME}/.var/app/${FF_FLATPAK_APP}/.mozilla/native-messaging-hosts/com.vestibule.usher.json" rm -f "${KIOSK_HOME}/snap/firefox/common/.mozilla/native-messaging-hosts/com.vestibule.usher.json" # XPI copies staged for sandbox-visible installs (flatpak/snap). rm -f "${KIOSK_HOME}/.var/app/${LW_FLATPAK_APP}/vestibule.xpi" rm -f "${KIOSK_HOME}/.var/app/${FF_FLATPAK_APP}/vestibule.xpi" rm -f "${KIOSK_HOME}/snap/firefox/common/vestibule.xpi" ok "manifests + sandbox XPI copies removed from ${KIOSK_HOME}" else info "kiosk account already absent — nothing to clean" fi # ─── 5. Optional removals ───────────────────────────────────────────── if [ "${REMOVE_USHER}" -eq 1 ]; then step "Remove usher binary" if [ -f "${USHER_DST}" ]; then rm -f "${USHER_DST}" ok "removed ${USHER_DST}" fi fi if [ "${REMOVE_OPT}" -eq 1 ]; then step "Remove ${OPT_ROOT}" if [ -d "${OPT_ROOT}" ]; then rm -rf "${OPT_ROOT}" ok "removed ${OPT_ROOT}" fi fi if [ "${REMOVE_USER}" -eq 1 ]; then step "Remove kiosk account" if [ -n "${KIOSK_HOME}" ]; then userdel -r "${KIOSK_USER}" || die 5 "userdel failed" ok "removed account '${KIOSK_USER}' and its home" else info "account already absent" fi fi step "Deprovisioning complete" info "next boot returns to the normal login prompt" exit 0