login greeter
git clone https://git.lucas.co/cce-display-manager.git
scripts/cce-gnome-keyring-start (2.1K)
1 #!/bin/sh
2 # cce-gnome-keyring-start — run gnome-keyring-daemon, unlocked, as ONE process.
3 #
4 # Two failures this shape is deliberately built around, both hit on 2026-08-29:
5 #
6 # 1. `gnome-keyring-daemon --unlock` does NOT exit — it daemonizes into a
7 # second keyring daemon. Two daemons racing for org.freedesktop.secrets is
8 # the same class of bug that made the old KeePassXC setup unpredictable.
9 # So the password goes into the daemon's own stdin at startup instead.
10 #
11 # 2. `systemd-creds decrypt` as a non-root user delegates to a polkit-gated
12 # root service. It succeeds in an interactive session and fails at login
13 # (io.systemd.InteractiveAuthenticationRequired), which wedged the greeter.
14 # tpm2-tools talks to /dev/tpmrm0 directly via the `tss` group — no agent,
15 # no prompt, no authorization step that can be absent at boot.
16 #
17 # Login here is by fingerprint, so PAM never sees a password and cannot unlock
18 # anything; the keyring password is sealed to the TPM instead.
19
20 set -eu
21
22 DIR="${CCE_KEYRING_DIR:-$HOME/.config/cce}"
23 PUB="$DIR/keyring-seal.pub"
24 PRIV="$DIR/keyring-seal.priv"
25
26 [ -r "$PRIV" ] || { echo "no TPM seal at $PRIV; run cce-gnome-keyring-enroll" >&2; exit 1; }
27
28 TMP=$(mktemp -d); trap 'rm -rf "$TMP"' EXIT INT TERM
29
30 # The TPM serializes, so a request racing another user of it fails
31 # transiently. Retry the whole unseal, primary key included.
32 n=0
33 until PW=$( { tpm2_createprimary -Q -C o -g sha256 -G ecc -c "$TMP/primary.ctx" \
34 && tpm2_load -Q -C "$TMP/primary.ctx" -u "$PUB" -r "$PRIV" -c "$TMP/seal.ctx" \
35 && tpm2_unseal -c "$TMP/seal.ctx"; } 2>&1 ); do
36 n=$((n + 1))
37 if [ "$n" -ge 5 ]; then
38 echo "TPM unseal failed after $n attempts: $PW" >&2
39 exit 1
40 fi
41 sleep 1
42 done
43
44 # --unlock reads the password from stdin and creates the login keyring if it is
45 # missing. --foreground keeps this under systemd instead of forking away.
46 printf '%s' "$PW" | exec gnome-keyring-daemon \
47 --foreground \
48 --components=pkcs11,secrets \
49 --unlock \
50 --control-directory="${XDG_RUNTIME_DIR:?XDG_RUNTIME_DIR unset}/keyring"