-
Notifications
You must be signed in to change notification settings - Fork 0
Troubleshooting
This is expected on v0.2.x. Sentinel doesn't ship a polkit agent yet,
so on desktops that have their own (cosmic-osd, polkit-gnome,
polkit-kde) you'll see both: the desktop's password prompt and
Sentinel's dialog (the latter spawned by pam_sentinel.so from
inside polkit-agent-helper-1).
It's fixable today by suppressing your desktop's agent — e.g. on cosmic-comp:
sudo chmod -x /usr/bin/cosmic-osd
# log out / log back inSide effect: you lose the desktop's volume/brightness OSDs that cosmic-osd handles. There's no per-feature toggle.
Since v0.4, a proper Sentinel polkit agent (Polkit Agent) ships that registers ahead of cosmic-osd's same-subject attempt — the duplicate UI is gone and you can leave cosmic-osd executable.
Symptom: after pkexec true (or any polkit-mediated action), the
journal shows event=auth.allow source=dialog ... instead of
event=auth.allow source=agent .... Both work, but the agent
path is faster (no fork + setuid + exec dance) and gives richer
process info in the dialog.
Root cause: the Sentinel polkit agent isn't currently the authoritative agent registered with polkitd. Verify with:
journalctl -t sentinel-polkit-agent --since "1 minute ago" --no-pager \
| grep -E "registered|already exists"If you see An authentication agent already exists for the given subject, another agent (typically cosmic-osd on COSMIC) won the
race after install or relogin. Since v0.5.1, Sentinel retries
registration up to 8 times with 500 ms backoff — it'll eventually
take over IF the competitor exits or backs off.
For session-supervised competitors that hard-respawn forever
(cosmic-session → cosmic-osd is the canonical case), the
only reliable workaround is to disable the competitor outright:
pkexec chmod -x /usr/bin/cosmic-osd # COSMIC users
# or
pkexec chmod -x /usr/lib/polkit-gnome-authentication-agent-1
pkexec chmod -x /usr/lib/polkit-kde-authentication-agent-1Side effect on COSMIC: you lose cosmic-osd's brightness/volume OSDs. There's no per-feature toggle. Sentinel becomes the sole polkit agent.
The fastest recovery, in order of preference:
Switch to a free TTY (Ctrl+Alt+F2 … F6), log in directly as root
(if root login is enabled) or as another user that doesn't go through
Sentinel:
# Inside the second shell, with root:
mv /etc/pam.d/sudo.pre-sentinel.bak /etc/pam.d/sudo
# or:
sed -i '/pam_sentinel/d' /etc/pam.d/sudo
# or:
/path/to/sentinel-source/uninstall.sh --yesReboot. At the boot loader (GRUB / systemd-boot), edit the kernel
command line and append init=/bin/bash. Boot. Filesystem will be
mounted read-only — remount r/w:
mount -o remount,rw /
mv /etc/pam.d/sudo.pre-sentinel.bak /etc/pam.d/sudo
sync && reboot -fBoot any Linux live USB, mount your root partition, edit
<mountpoint>/etc/pam.d/sudo directly. Same fix as above.
If the install state file is intact, the cleanest recovery from any of the above is:
cd /path/to/sentinel-source
./uninstall.sh --yes # already running as root in the recovery shellThis restores every file Sentinel touched (including any pre-existing
polkit-1 / sudo you'd customised before installing).
Check, in order:
# 1. Is the PAM module loaded? (you should see this every sudo attempt)
journalctl -t pam_sentinel -f
# 2. Is the helper installed and runnable?
ls -l /usr/lib/sentinel-helper /usr/lib/security/pam_sentinel.so
# 3. Does the helper run by hand?
/usr/lib/sentinel-helper --timeout 10 --randomize --process-exe /usr/bin/sudo
# 4. Is your compositor providing zwlr-layer-shell-v1?
grep -r layer_shell /usr/share/wayland-sessions # rough check
# or: weston-info | grep layer-shell (if weston-info is installed)
# 5. Are you on GNOME/Mutter? (Mutter doesn't implement layer-shell)
echo "$XDG_CURRENT_DESKTOP"If WAYLAND_DISPLAY isn't set in the user environment that PAM sees
(some screen lockers / login flows scrub it), the helper exits DENY
silently and PAM falls through to pam_unix — you get a password
prompt instead of the dialog. With headless_action = "password"
this is the correct fallback.
The install script's verify step caught a file with the wrong permissions. Likely cause: a previous failed install left a half-written file. Easiest fix:
pkexec ./uninstall.sh --yes # cleans up via state file
pkexec ./install.shThe helper is Wayland-only. It doesn't run on X11, headless, or SSH.
This is intentional — for headless paths, the PAM module returns
PAM_IGNORE and the password fallback runs at the PAM layer.
You can still smoke-test the helper from a Wayland session:
just helper-testYou're on a pre-0.2.0 build. The session-lock plan was dropped in v0.2.0 — upgrade and the warning is gone.
GNOME (Mutter) doesn't implement zwlr-layer-shell-v1, so the overlay
won't render. Two options:
- Run with
--windowed(debug fallback to xdg-toplevel — doesn't block input or grab keyboard, just a regular window). - Use a different Wayland compositor (cosmic-comp, Hyprland, Sway, KWin/Wayland) for sessions that you want gated by Sentinel.
This is a Mutter limitation we can't work around from inside the helper.
The helper exits via cosmic::iced::exit(). If it hangs, the
compositor probably refused to destroy the layer surface — kill it:
pkill sentinel-helperPAM's safety-margin poll (helper timeout + 5 s) will SIGKILL it automatically; users won't be permanently stuck.
If log_attempts = true is too chatty, set it to false per service:
[services.polkit-1]
log_attempts = falseOr globally in [general]. The default is true because losing the
audit trail on a security tool is worse than the syslog noise.
The PAM module logs to syslog facility auth. To get more verbose
logs, build with RUST_LOG=debug and add debug to the PAM line:
auth sufficient pam_sentinel.so debug
This is recognised by libpam as a generic flag and is forwarded to
the module. Most third-party PAM modules treat it as "log everything";
pam_sentinel follows the same convention.
# Source build:
git pull
pkexec ./install.sh # re-runs all of install, replacing files
# AUR:
yay -Syu sentinel # or sentinel-git
# Debian / RPM:
sudo apt install ./sentinel_$NEW_VERSION-1_amd64.deb
sudo dnf install ./sentinel-$NEW_VERSION-1.x86_64.rpminstall.sh is idempotent — re-running it is the supported upgrade
path. The state file and .pre-sentinel.bak files are preserved across
re-runs (your original pre-Sentinel files don't get overwritten).
Since v0.5, install.sh also restarts the running polkit agent in
place — you no longer need to log out + back in for the new binary
to take effect on upgrade. This requires the install script to be
running in a session whose audit sessionid matches the compositor's
(the typical case when you launched it from a terminal opened by the
compositor); if the sessionids differ, the script logs a warning and
falls back to "the new agent will activate at next login".
The helper picks a locale from LC_ALL → LC_MESSAGES → LANG. If none
matches one of the embedded bundles (en-US, de-DE, es-ES,
fr-FR, it-IT, ja-JP, nl-NL, pl-PL, pt-BR, ru-RU,
tr-TR, zh-CN), the helper silently falls back to en-US.
For the PAM-spawned dialog path (sudo, pkexec via PAM), the
locale env vars are scrubbed by the privileged binary before
pam_sentinel.so runs. v0.5 recovers them by reading the requesting
user's /proc/<pid>/environ. If you've explicitly cleared LANG in
your shell or your terminal doesn't propagate it, you'll see the
fallback. Check with:
env | grep -E '^LC_|^LANG=' | headFor the polkit agent path (anything that triggers
sentinel-polkit-agent's dialog), the agent inherits env from your
compositor at autostart time. Logging out / back in after changing
your shell's LANG defaults is the cleanest way to update it.
GNOME's Mutter doesn't implement zwlr-layer-shell-v1, so prior to
v0.5 the helper hard-failed on GNOME. v0.5 detects GNOME-family
desktops via XDG_CURRENT_DESKTOP and auto-falls back to
--windowed mode (a regular xdg-toplevel window instead of the
full-screen overlay). You should see a one-line stderr notice when
this kicks in:
sentinel-helper: detected compositor without zwlr-layer-shell-v1 …
Override either way: --layer-shell to force the overlay even on
GNOME (will fail), --windowed to force the regular window even
elsewhere (debugging).
Auth-outcome events are structured key=value lines (logfmt) since v0.5:
# Last 50 auth events, JSON-formatted:
journalctl -t pam_sentinel -t sentinel-polkit-agent --output=json -n 50 \
| jq 'select(.MESSAGE | startswith("event=auth.")) | .MESSAGE'
# Just the denials in the last hour:
journalctl -t pam_sentinel -t sentinel-polkit-agent --since "1 hour ago" \
| grep "event=auth.deny"
# Latency distribution:
journalctl -t pam_sentinel -t sentinel-polkit-agent --since today \
| grep -oP 'latency_ms=\K\d+' | sort -n | uniq -cFields available:
-
event—auth.allow/auth.deny/auth.timeout/auth.error -
source—dialog/bypass/headless/agent/agent.bypass -
user,service,action,process,uid,peer_pid,latency_ms
GPL-3.0-or-later. Provided as-is, without warranty of any kind (GPL §15-16). Use at your own risk on production systems.