fix(terminal+journal): run as root via sudo + add bfkiosk NOPASSWD sudoers

Terminal spawns bash as bfkiosk (unprivileged) → can't read journal,
can't run rauc/systemctl, can't fix anything useful. Now runs
sudo bash --login (with fallback to plain bash if sudo unavailable).

Journal streaming: sudo journalctl instead of plain journalctl so
bfkiosk can read system journal without systemd-journal group.

Pi-gen image: drops /etc/sudoers.d/betterframe-kiosk granting bfkiosk
passwordless sudo. Gated by the on-screen code + lockout ladder, so
root access still requires physical presence.
This commit is contained in:
Mitchell R 2026-05-22 23:30:13 +02:00
parent 4cf9704350
commit 6244fe26e0
No known key found for this signature in database
2 changed files with 22 additions and 5 deletions

View file

@ -13,6 +13,10 @@ for grp in video render input audio; do
fi fi
done done
# --- Passwordless sudo for bfkiosk (remote terminal runs as root) ---
echo 'bfkiosk ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/betterframe-kiosk
chmod 440 /etc/sudoers.d/betterframe-kiosk
# --- Binary --- # --- Binary ---
install -d -o bfkiosk -g bfkiosk -m 755 /opt/betterframe/kiosk install -d -o bfkiosk -g bfkiosk -m 755 /opt/betterframe/kiosk
install -m 755 /tmp/bf-files/betterframe-kiosk /opt/betterframe/kiosk/betterframe-kiosk install -m 755 /tmp/bf-files/betterframe-kiosk /opt/betterframe/kiosk/betterframe-kiosk

View file

@ -121,9 +121,9 @@ impl JournalStream {
let kill_clone = kill.clone(); let kill_clone = kill.clone();
std::thread::spawn(move || { std::thread::spawn(move || {
// Try unit-scoped first, fall back to all journal if permission denied. // Use sudo so bfkiosk user can read system journal.
let mut child = match Command::new("journalctl") let mut child = match Command::new("sudo")
.args(["--user-unit", "betterframe-kiosk", "-f", "--no-pager", "-o", "short-iso", "-n", "50"]) .args(["journalctl", "-u", "betterframe-kiosk", "-f", "--no-pager", "-o", "short-iso", "-n", "50"])
.stdout(Stdio::piped()) .stdout(Stdio::piped())
.stderr(Stdio::piped()) .stderr(Stdio::piped())
.spawn() .spawn()
@ -219,13 +219,26 @@ pub struct TerminalSession {
impl TerminalSession { impl TerminalSession {
pub fn spawn() -> Result<(Self, std::process::ChildStdout, std::process::ChildStderr), String> { pub fn spawn() -> Result<(Self, std::process::ChildStdout, std::process::ChildStderr), String> {
let mut child = Command::new("bash") // Run as root so the operator can actually fix things (journal,
// rauc, systemctl, usermod). The on-screen code + lockout ladder
// gates access; once past that, full root is the point.
let mut child = Command::new("sudo")
.args(["bash", "--login"])
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.env("TERM", "xterm-256color")
.spawn()
.or_else(|_| {
// Fallback if sudo not available / not configured for bfkiosk.
Command::new("bash")
.args(["--login"]) .args(["--login"])
.stdin(Stdio::piped()) .stdin(Stdio::piped())
.stdout(Stdio::piped()) .stdout(Stdio::piped())
.stderr(Stdio::piped()) .stderr(Stdio::piped())
.env("TERM", "xterm-256color") .env("TERM", "xterm-256color")
.spawn() .spawn()
})
.map_err(|e| format!("bash spawn: {e}"))?; .map_err(|e| format!("bash spawn: {e}"))?;
let stdout = child.stdout.take().ok_or("no stdout")?; let stdout = child.stdout.take().ok_or("no stdout")?;