Files
fblogin/README.md
2025-10-22 05:04:19 -04:00

357 lines
9.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/¯¯¯¯/\¯¯¯¯\·. ''/¯¯¯¯/\¯¯¯¯\·. |¯¯¯¯|`·.' '/¯¯¯¯/\¯¯¯¯\`·.''/¯¯¯¯/\¯¯¯¯\·. |¯¯¯¯|`·.'/¯¯¯¯/`·.
|`·.·´`·|::'¯¯¯¯`·.\|·´`·.·´|:/____/`·.|`·.·´`·|:::' |·´`·.·´|::|`·.·´`·|:::|`·.·´`·|:::¯¯¯¯`·.\|.·´`·.·|:::|.·´`·.·|\¯¯¯¯\`·.
|`·.·´`·|\¯¯¯¯\·.¨ '|·´`·.·´|:\¯¯¯¯\·./|`·.·´`·|::|¯¯¯¯|`·.|·´`·.·´|::|`·.·´`·|:::|`·.·´`·|:\¯¯¯¯\·. ¨|.·´`·.·|:::|.·´`·.·|:|`·.·´`·|:::'
|____|::¯¯¯¯`·.\''\____\/____/`·.'\____\/____/`·.''\____\/____/`·.''\____\/____/`·. |____|:::|____|:|____|:::'
'`·.:::::`·.¨ ¨ ¨ ¨ ¨ ' `·.::::::::::::'`·./ `·.::::::::::::'`·./' '`·.:::::::::::::`·./' `·.::::::::::::'`·./ '`·.:::::`·.'`·.:::::`·`·.::::`·.
# fblogin — framebuffer login for tty1
Framebuffer greeter that:
- draws directly to **fbdev** (no X/Wayland),
- authenticates via **PAM** (optional fprintd),
- binds a **logind** session on **tty1**,
- execs a **real login shell** on the same VT.
---
## Quick start
```bash
# Debian/Ubuntu deps
sudo apt-get install -y build-essential libpam0g-dev libfprint-dev fprintd pkg-config
# build + install (binary, unit, pam, banner, manpage)
make
sudo make install-all
# logging (global file, debug on)
sudo install -d -m 0755 /var/log/fblogin
sudo install -m 0640 /dev/null /var/log/fblogin/fblogin.log
sudo chown root:adm /var/log/fblogin/fblogin.log
# unit env (drop-in)
sudo systemctl edit fblogin@tty1.service
# [Service]
# Environment=FBLOGIN_DEBUG=1
# Environment=FBLOGIN_LOG_FILE=/var/log/fblogin/fblogin.log
# logrotate (SIGUSR1 reopen)
sudo tee /etc/logrotate.d/fblogin >/dev/null <<'ROT'
/var/log/fblogin/fblogin.log {
rotate 7
daily
missingok
notifempty
compress
create 0640 root adm
postrotate
systemctl kill -s SIGUSR1 fblogin@tty1.service 2>/dev/null || true
endscript
}
ROT
sudo systemctl daemon-reload
sudo systemctl enable --now fblogin@tty1.service
```
Switch to tty1, log in (fingerprint or password). You land in a login shell on tty1; start your session from there (e.g., `startx`).
---
## Contents
- [Scope](#scope)
- [Features](#features)
- [Repository layout](#repository-layout)
- [Build/install targets](#buildinstall-targets)
- [Systemd integration](#systemd-integration)
- [PAM stack](#pam-stack)
- [Authentication flow](#authentication-flow)
- [Session model](#session-model)
- [TTY/signals](#ttysignals)
- [Logging modes](#logging-modes)
- [Xauthority/startx notes](#xauthoritystartx-notes)
- [setup.sh](#setupsh)
- [Man page](#man-page)
- [Security](#security)
- [Troubleshooting](#troubleshooting)
- [Contributing / License / Docs](#contributing--license--docs)
---
## Scope
**Is**
- Greeter for **tty1** using fbdev.
- PAM client that opens a proper **logind** session.
- Hands control to a login shell; session startup remains user-controlled.
**Is not**
- Full display manager (no seat juggling, no VT switching).
- Compositor or X/Wayland launcher.
- Aggressive manager of `.Xauthority` (guidance only).
---
## Features
- **Env-aware logging**
- `FBLOGIN_DEBUG=1` toggles debug.
- `FBLOGIN_LOG_FILE=…` pins a global log file (no per-user switch).
- `SIGUSR1` reopens the forced log (for logrotate).
- **CLI**
- `--help`, `--version` (from `include/version.h`)
- `--log-file=/path` (implies debug; pins logging)
- `--no-fp`, `--fp-max=N` (UI hint; PAM remains authoritative)
- `--dev` (relax in-session guard), `--debug`
- **Greeter keeper**
- Greeter PAM session in a child, held open until auth, then closed.
- **sd-login diagnostics** (if linked with libsystemd)
- **Self-pipe signal wakeups** (no SA_RESTART surprises)
---
## Repository layout
```
include/
config.h fb.h input.h pam_auth.h ui.h version.h
man/
fblogin.1
src/
fb.c input.c pam_auth.c ui.c main.c
system/
systemd/fblogin@.service
pamd/fblogin
issue/issue.fblogin
docs/
ARCHITECTURE.md CHANGELOG.md Contributing.md TODO.md
Makefile
setup.sh
README.md
```
---
## Build/install targets
Variables:
- `PREFIX=/usr/local` (default)
- `BINDIR=$(PREFIX)/bin`
- `MANPREFIX=$(PREFIX)/share/man`, `MAN1DIR=$(MANPREFIX)/man1`
- `ISSUE_FILE=system/issue/issue.fblogin`
Targets:
```make
make # build
make debug|release|asan
sudo make install # binary (4755)
sudo make install-systemd # unit
sudo make install-pam # /etc/pam.d/fblogin
sudo make install-issue # /etc/issue.fblogin (optional)
sudo make install-man # manpage
sudo make install-all # all above
sudo make uninstall
sudo make uninstall-systemd
sudo make uninstall-pam
sudo make uninstall-issue
sudo make uninstall-man
sudo make uninstall-all
```
Uninstall is symmetric with defaults. If you changed `PREFIX`/`MAN*`, pass the same values to uninstall.
---
## Systemd integration
Installed unit (`system/systemd/fblogin@.service`):
```ini
[Unit]
Description=Framebuffer Login on %I
Documentation=man:systemd-logind.service(8) man:logind.conf(5)
After=systemd-user-sessions.service plymouth-quit-wait.service
Conflicts=getty@%i.service
ConditionPathExists=/dev/%I
[Service]
TTYPath=/dev/%I
TTYReset=yes
TTYVHangup=yes
StandardInput=tty
StandardOutput=tty
StandardError=tty
PAMName=fblogin
UtmpIdentifier=%I
UtmpMode=user
ExecStart=/usr/local/bin/fblogin
Type=simple
Restart=always
RestartSec=1
[Install]
WantedBy=multi-user.target
```
Recommended drop-in:
```ini
[Service]
Environment=FBLOGIN_DEBUG=1
Environment=FBLOGIN_LOG_FILE=/var/log/fblogin/fblogin.log
```
Logrotate:
```conf
/var/log/fblogin/fblogin.log {
rotate 7
daily
missingok
notifempty
compress
create 0640 root adm
postrotate
systemctl kill -s SIGUSR1 fblogin@tty1.service 2>/dev/null || true
endscript
}
```
---
## PAM stack
`/etc/pam.d/fblogin`:
```
auth include common-auth
account include common-account
password include common-password
session required pam_env.so
session required pam_loginuid.so
session include common-session
session required pam_systemd.so
```
- `pam_loginuid.so` sets `/proc/self/loginuid`.
- `pam_systemd.so` registers the session with logind.
---
## Authentication flow
- Username field first; `Tab` toggles focus.
- If password is empty and fingerprints are enabled, try the **fingerprint** path via PAM.
- On success: welcome screen → stop greeter keeper → exec users login shell.
- On failure: prompt for password and proceed via PAM.
Disable fingerprints:
- `--no-fp` or `FBLOGIN_FINGERPRINT=0`.
---
## Session model
- Runs on **tty1** (`TTYPath` + `UtmpMode=user`).
- Opens the user **PAM** session; logind sees `CLASS=user TYPE=tty`.
- Drops to users uid/gid, sets `HOME/SHELL/USER/LOGNAME` (+ fallback `PATH`), execs the login shell with `-l`.
- Start the graphical session from that shell (e.g., `startx`).
---
## TTY/signals
- `SIGTERM`: graceful shutdown via self-pipe to break `poll(2)`.
- `SIGUSR1`: reopen forced log file.
- `SIGINT`, `SIGQUIT`, `SIGTSTP`: ignored.
Keys:
- `Tab` toggle focus, `Ctrl-U` clear focused field, `Ctrl-R` reset both, `Ctrl-D` restart greeter UI.
---
## Logging modes
- **Default**: pre-user logs to `/tmp/fblogin-$pid.log`; after username known, switch to `$HOME/.fblogin.log` (600, chowned).
- **Forced global**: set `FBLOGIN_LOG_FILE=/var/log/fblogin/fblogin.log` or pass `--log-file=/path`. Remains on that file and never switches. `SIGUSR1` triggers reopen. Requires `FBLOGIN_DEBUG=1` or `--debug` (implied by `--log-file`).
---
## Xauthority/startx notes
Do not export `XAUTHORITY` globally in `~/.zshenv`.
If keeping Xauthority under `XDG_RUNTIME_DIR` **only on tty1**, add to `~/.config/zsh/.zlogin`:
```zsh
if [[ -z "$DISPLAY" && -z "$SSH_TTY" && "$(tty)" == "/dev/tty1" ]]; then
if [[ -n "$XDG_RUNTIME_DIR" && -O "$XDG_RUNTIME_DIR" ]]; then
AUTH="${XDG_RUNTIME_DIR}/x11/Xauthority"
install -d -m 700 -- "${AUTH:h}"
if [[ ! -L "$HOME/.Xauthority" || "$(readlink -f "$HOME/.Xauthority" 2>/dev/null)" != "$AUTH" ]]; then
rm -f -- "$HOME/.Xauthority"
ln -s -- "$AUTH" "$HOME/.Xauthority"
fi
# exec startx # optional
fi
fi
```
`~/.xinitrc` should not hard-set `XAUTHORITY`; let `xinit/xauth` manage cookies. It can export env to user services if needed.
---
## setup.sh
Automates:
- PAM file write,
- unit install,
- removal of conflicting `getty@tty1` override,
- disabling getty on tty1/tty2,
- enabling `fblogin@tty1`,
- basic verification.
Run with root: `sudo ./setup.sh`.
---
## Man page
Install via `make install-man`, then `man fblogin`.
---
## Security
- Binary is **setuid root** (4755).
- PAM handles credentials; we dont store them.
- Greeter session isolated; user session opened/closed explicitly.
- Minimal signal surface; blocking calls interrupted safely.
---
## Troubleshooting
- **stdin is not a TTY**: start via `fblogin@tty1.service` on a VT.
- **PAM session failed (TTY busy / inside a session)**: use a free VT; dont launch inside an existing session unless `--dev`.
- **polkit prompts missing**: ensure DE/WM started from the tty-backed session (`loginctl` should show `TYPE=tty`).
- **fingerprint never matches**: enroll with `fprintd-enroll`, confirm sensor support; disable with `--no-fp` if needed.
- **logs break after rotation**: use the provided logrotate and `SIGUSR1` reopen; ensure forced global logging is configured.
- **no /dev/fb0**: fbdev not exposed; current code targets fbdev, not DRM/KMS.
---
## Contributing / License / Docs
- Contribution guide: `docs/Contributing.md`
- Architecture notes: `docs/ARCHITECTURE.md`
- Changelog: `docs/CHANGELOG.md`
- License: `LICENSE`