#!/bin/bash
# =============================================================================
# kiosk-manager.sh — Debian 13 (Trixie)
# Arquitectura: lightdm autologin → openbox → chromium --kiosk
# lightdm gestiona sesión logind y seat correctamente (sin entorno gráfico)
# Requiere: root
# =============================================================================
SELECTED_USER=""
BROWSER_BIN=""
# ─── utilidades ───────────────────────────────────────────────────────────────
check_root() {
[[ "$EUID" -ne 0 ]] && { echo "❌ Ejecutar como root"; exit 1; }
}
detect_browser() {
BROWSER_BIN=$(command -v firefox-esr 2>/dev/null || command -v firefox 2>/dev/null || true)
}
pause() {
echo ""
read -rp " Pulsa ENTER para continuar..."
}
user_home() {
getent passwd "$1" | cut -d: -f6
}
# ─── 1. Crear usuario ─────────────────────────────────────────────────────────
create_user() {
echo ""
echo " ╔─ PASO 1: Crear usuario kiosk ──────────────────────╗"
echo ""
read -rp " Nombre de usuario: " NEW_USER
echo ""
if [ -z "$NEW_USER" ]; then
echo " ❌ Nombre vacío"
pause; return 1
fi
if id "$NEW_USER" &>/dev/null; then
echo " ⚠ El usuario '$NEW_USER' ya existe"
read -rp " ¿Usar este usuario? [s/N]: " yn
[[ "$yn" != "s" && "$yn" != "S" ]] && { pause; return 1; }
SELECTED_USER="$NEW_USER"
echo " ✔ Usando: $SELECTED_USER"
else
adduser \
--disabled-password \
--gecos "Kiosk" \
--shell /bin/bash \
"$NEW_USER"
passwd -l "$NEW_USER"
SELECTED_USER="$NEW_USER"
echo ""
echo " ✔ Usuario creado: $SELECTED_USER"
fi
echo ""
echo " Aplicando privilegios mínimos..."
# video y render se mantienen: necesarios para acceso GPU
for grp in sudo adm dialout cdrom floppy plugdev netdev; do
deluser "$SELECTED_USER" "$grp" 2>/dev/null || true
done
usermod -aG video "$SELECTED_USER"
usermod -aG render "$SELECTED_USER" 2>/dev/null || true
echo " ✔ Grupos configurados (video y render incluidos para GPU)"
echo ""
echo " ╚────────────────────────────────────────────────────╝"
pause
}
# ─── 2. Instalar paquetes ─────────────────────────────────────────────────────
install_packages() {
echo ""
echo " ╔─ PASO 2: Instalar paquetes ────────────────────────╗"
echo ""
echo " Actualizando índice..."
apt-get update -qq
echo " Instalando stack X + lightdm + openbox + firefox-esr..."
# lightdm: display manager — gestiona sesión logind y seat
# lightdm-gtk-greeter: greeter requerido por lightdm (no visible con autologin)
# openbox: WM mínimo sin compositor ni escritorio
# chromium: navegador kiosk
# x11-xserver-utils: xset (screensaver/DPMS)
# x11-utils: xrandr
# unclutter-xfixes: ocultar cursor
# fonts-liberation: fuentes base para chromium
apt-get install -y --no-install-recommends \
lightdm \
lightdm-gtk-greeter \
openbox \
x11-xserver-utils \
x11-utils \
unclutter-xfixes \
fonts-liberation
detect_browser
if [ -z "$BROWSER_BIN" ]; then
echo " ❌ Firefox ESR no encontrado tras la instalación"
pause; return 1
fi
echo ""
echo " ✔ Firefox ESR: $BROWSER_BIN"
echo " ✔ lightdm instalado"
echo " ✔ openbox instalado"
echo ""
echo " ╚────────────────────────────────────────────────────╝"
pause
}
# ─── 3. Configurar kiosk ──────────────────────────────────────────────────────
setup_kiosk() {
echo ""
echo " ╔─ PASO 3: Configurar kiosk ─────────────────────────╗"
echo ""
if [ -z "$SELECTED_USER" ]; then
echo " ❌ Ejecuta primero el Paso 1"
pause; return 1
fi
if ! id "$SELECTED_USER" &>/dev/null; then
echo " ❌ Usuario '$SELECTED_USER' no existe"
pause; return 1
fi
detect_browser
if [ -z "$BROWSER_BIN" ]; then
echo " ❌ Firefox ESR no instalado — ejecuta primero el Paso 2"
pause; return 1
fi
local url
while true; do
read -rp " URL del kiosk: " url
[[ "$url" =~ ^https?:// ]] && break
echo " ❌ Debe empezar por http:// o https://"
done
local home_dir
home_dir=$(user_home "$SELECTED_USER")
echo ""
# ── [1/6] Limpiar configuración anterior si existe ────────────────────────
echo " [1/6] Limpiando configuración anterior..."
rm -f "$home_dir/.bash_profile"
rm -rf "/etc/systemd/system/getty@tty7.service.d"
systemctl daemon-reload 2>/dev/null || true
echo " ✔ Limpieza completada"
# ── [2/6] Openbox: rc.xml sin keybindings ni menú ────────────────────────
echo " [2/6] Configurando Openbox..."
local ob_dir="$home_dir/.config/openbox"
mkdir -p "$ob_dir"
# rc.xml: sin atajos de teclado, sin menú contextual, Chromium fullscreen
cat > "$ob_dir/rc.xml" <<'EOF'
yes
no
1
1
0
0000
C-g
1
200
0
false
no
true
true
yes
above
1
no
true
true
yes
above
1
EOF
cat > "$ob_dir/menu.xml" <<'EOF'
EOF
# autostart: lanza Chromium al arrancar openbox
cat > "$ob_dir/autostart" </dev/null && unclutter --timeout 3 --fork
# Esperar a que openbox inicialice completamente
sleep 1
# Chromium en modo kiosk
$BROWSER_BIN \\
--kiosk "$url" \\
\
--no-first-run \\
--no-sandbox \\
--disable-infobars \\
--disable-session-crashed-bubble \\
--disable-translate \\
--disable-extensions \\
--disable-sync \\
--disable-background-networking \\
--disable-features=TranslateUI \\
--check-for-update-interval=31536000 \\
--noerrdialogs &
EOF
chown -R "$SELECTED_USER":"$SELECTED_USER" "$ob_dir"
echo " ✔ Openbox configurado (sin keybindings, sin menú)"
# ── [3/6] Guardar URL ─────────────────────────────────────────────────────
echo "$url" > "$home_dir/.kiosk_url"
chown "$SELECTED_USER":"$SELECTED_USER" "$home_dir/.kiosk_url"
# ── [4/6] lightdm: autologin directo al usuario kiosk ────────────────────
# lightdm gestiona correctamente:
# - sesión logind (seat0 asignado)
# - acceso a dispositivos DRM/GPU via logind
# - D-Bus de sesión
# Con autologin-user-timeout=0 el greeter no se muestra nunca
echo " [4/6] Configurando lightdm autologin..."
mkdir -p /etc/lightdm/lightdm.conf.d
cat > /etc/lightdm/lightdm.conf.d/kiosk.conf </dev/null || true
sleep 1
# Desmontar overlay previo si existe
umount "/home/$SELECTED_USER" 2>/dev/null || true
# Crear copia base del home ya configurado
rm -rf "$base_dir"
mkdir -p "$base_dir"
cp -a "$home_dir/." "$base_dir/"
echo " ✔ Base guardada en: $base_dir"
# Servicio systemd que monta el overlay ANTES de que lightdm arranque
cat > "/etc/systemd/system/kiosk-overlay-${SELECTED_USER}.service" </dev/null)"
printf " lightdm : %s\n" "$(systemctl is-active lightdm 2>/dev/null)"
echo ""
echo " ── Autologin configurado ────────────────────────────"
local conf="/etc/lightdm/lightdm.conf.d/kiosk.conf"
if [ -f "$conf" ]; then
grep -E "autologin-user=|autologin-session=" "$conf"
else
echo " ⚠ Sin configuración de autologin"
fi
echo ""
echo " ── OverlayFS ────────────────────────────────────────"
if mount | grep -q 'overlay on /home'; then
mount | grep 'overlay on /home' | awk '{printf " ✔ Activo: %s\n", $3}'
else
echo " ⚠ Overlay no montado (reinicia para activarlo)"
fi
echo ""
echo " ── lightdm ──────────────────────────────────────────"
systemctl status lightdm --no-pager --lines=5
echo ""
echo " ── Procesos kiosk activos ───────────────────────────"
ps aux | grep -E "Xorg|openbox|firefox|lightdm" | grep -v grep \
| awk '{printf " %-12s %s\n", $1, $11}' \
|| echo " (ninguno)"
pause
}
# ─── desinstalar ──────────────────────────────────────────────────────────────
uninstall_kiosk() {
echo ""
echo " Usuarios disponibles (UID ≥ 1000):"
echo " ------------------------------------"
getent passwd | awk -F: '$3 >= 1000 && $3 < 65534 { print " " $1 }' | sort
echo " ------------------------------------"
read -rp " Usuario a desinstalar: " DEL_USER
if ! id "$DEL_USER" &>/dev/null; then
echo " ❌ Usuario '$DEL_USER' no existe"
pause; return 1
fi
local home_dir
home_dir=$(user_home "$DEL_USER")
echo ""
echo " ⚠ Se eliminará la configuración kiosk de: $DEL_USER"
echo " El usuario y su home NO se borran"
read -rp " ¿Confirmar? [s/N]: " confirm
[[ "$confirm" != "s" && "$confirm" != "S" ]] && { echo " Cancelado"; pause; return; }
echo ""
# Matar sesión activa
pkill -u "$DEL_USER" 2>/dev/null && echo " ✔ Sesión terminada" || true
# Desmontar y eliminar overlay
umount "/home/$DEL_USER" 2>/dev/null || true
systemctl stop "kiosk-overlay-${DEL_USER}.service" 2>/dev/null || true
systemctl disable "kiosk-overlay-${DEL_USER}.service" 2>/dev/null || true
rm -f "/etc/systemd/system/kiosk-overlay-${DEL_USER}.service"
rm -rf "/opt/kiosk-base/$DEL_USER"
rm -rf "/run/kiosk-${DEL_USER}-upper" "/run/kiosk-${DEL_USER}-work"
echo " ✔ Overlay eliminado"
# Eliminar configuración lightdm
rm -f /etc/lightdm/lightdm.conf.d/kiosk.conf
echo " ✔ Configuración lightdm eliminada"
# Deshabilitar lightdm
systemctl disable lightdm 2>/dev/null || true
systemctl set-default multi-user.target
echo " ✔ lightdm deshabilitado"
# Eliminar configuración X del usuario
rm -f "$home_dir/.kiosk_url"
rm -f "$home_dir/.config/openbox/rc.xml"
rm -f "$home_dir/.config/openbox/menu.xml"
rm -f "$home_dir/.config/openbox/autostart"
echo " ✔ Configuración openbox eliminada"
[ "$SELECTED_USER" = "$DEL_USER" ] && SELECTED_USER=""
echo ""
echo " ✔ Desinstalado correctamente"
pause
}
# ─── menú ─────────────────────────────────────────────────────────────────────
menu() {
clear
detect_browser
local lightdm_status
lightdm_status=$(systemctl is-active lightdm 2>/dev/null || echo "inactivo")
echo ""
echo " ╔══════════════════════════════════════════════╗"
echo " ║ KIOSK MANAGER — Debian 13 (Trixie) ║"
echo " ╠══════════════════════════════════════════════╣"
printf " ║ Usuario : %-33s║\n" "${SELECTED_USER:-}"
printf " ║ Browser : %-33s║\n" "${BROWSER_BIN:-}"
printf " ║ lightdm : %-33s║\n" "$lightdm_status"
echo " ╠══════════════════════════════════════════════╣"
echo " ║ ║"
echo " ║ 1) Crear usuario kiosk ║"
echo " ║ 2) Instalar paquetes ║"
echo " ║ 3) Configurar kiosk ║"
echo " ║ ───────────────────────────── ║"
echo " ║ 4) Estado ║"
echo " ║ 5) Desinstalar kiosk ║"
echo " ║ 6) Salir ║"
echo " ║ ║"
echo " ╚══════════════════════════════════════════════╝"
echo ""
read -rp " Opción: " opt
echo ""
case "$opt" in
1) create_user ;;
2) install_packages ;;
3) setup_kiosk ;;
4) status ;;
5) uninstall_kiosk ;;
6) echo " Saliendo..."; exit 0 ;;
*) echo " ⚠ Opción no válida"; sleep 1 ;;
esac
}
# ─── entrada ──────────────────────────────────────────────────────────────────
check_root
while true; do menu; done