login greeter
git clone https://git.lucas.co/cce-display-manager.git
scripts/cce-gnome-keyring-start (2.4K)
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 #
33 # stderr goes to a file, never into PW: tpm2-tools and the TSS print warnings
34 # on stderr even when the unseal succeeds, and with `2>&1` (until 2026-10-02)
35 # any such line was prepended to the password, the unlock failed and the
36 # keyring stayed locked.
37 n=0
38 until PW=$( { tpm2_createprimary -Q -C o -g sha256 -G ecc -c "$TMP/primary.ctx" \
39 && tpm2_load -Q -C "$TMP/primary.ctx" -u "$PUB" -r "$PRIV" -c "$TMP/seal.ctx" \
40 && tpm2_unseal -c "$TMP/seal.ctx"; } 2>"$TMP/err" ); do
41 n=$((n + 1))
42 if [ "$n" -ge 5 ]; then
43 echo "TPM unseal failed after $n attempts: $(cat "$TMP/err")" >&2
44 exit 1
45 fi
46 sleep 1
47 done
48
49 # --unlock reads the password from stdin and creates the login keyring if it is
50 # missing. --foreground keeps this under systemd instead of forking away.
51 printf '%s' "$PW" | exec gnome-keyring-daemon \
52 --foreground \
53 --components=pkcs11,secrets \
54 --unlock \
55 --control-directory="${XDG_RUNTIME_DIR:?XDG_RUNTIME_DIR unset}/keyring"