Files
dotfiles/.memory/research/SDDM KWallet PAM Setup for Hyprland.md
2026-03-12 12:14:33 +00:00

265 lines
12 KiB
Markdown

---
title: SDDM KWallet PAM Setup for Hyprland
type: note
permalink: dotfiles/research/sddm-kwallet-pam-setup-for-hyprland
tags:
- sddm
- kwallet
- pam
- hyprland
- arch
- research
- authoritative
---
# SDDM KWallet PAM Setup for Hyprland
## Summary
Complete, source-verified setup for automatic KWallet unlock on SDDM password login, for a non-Plasma (Hyprland) Arch Linux system.
## Freshness
- confidence: high
- last_validated: 2026-03-11
- volatility: low (KDE Plasma 6 PAM module is stable; Arch Wiki last edited 2026-03-10)
- review_after_days: 90
- validation_count: 1
- contradiction_count: 0
## Sources consulted
- [source] Arch Wiki "KDE Wallet" — https://wiki.archlinux.org/title/KDE_Wallet (last edited 2026-03-10)
- [source] Arch Wiki "SDDM" — https://wiki.archlinux.org/title/SDDM (last edited 2026-03-04)
- [source] Arch package database `kwallet-pam` 6.6.2-1 file listing — https://archlinux.org/packages/extra/x86_64/kwallet-pam/files/
- [source] Arch package database `kwallet` 6.23.0-1 file listing — https://archlinux.org/packages/extra/x86_64/kwallet/files/
- [source] Real-world Hyprland dotfiles from GitHub (wayblueorg/wayblue, AhmedAmrNabil/nix-config)
## (1) Package to install
- [fact] Package: **`kwallet-pam`** — in the official **`extra`** repository (NOT AUR)
- [fact] Install command: `sudo pacman -S kwallet-pam`
- [fact] Current version: **6.6.2-1** (as of 2026-03-03)
- [fact] Dependencies: `kwallet`, `pam`, `libgcrypt`, `socat` (all already present or auto-resolved)
- [fact] Files installed:
- `/usr/lib/security/pam_kwallet5.so` — the PAM module
- `/usr/lib/pam_kwallet_init` — session-start helper script
- `/etc/xdg/autostart/pam_kwallet_init.desktop` — XDG autostart for Plasma/DE environments
- `/usr/lib/systemd/user/plasma-kwallet-pam.service` — systemd user service
### Critical naming fact
- [fact] **The PAM module is `pam_kwallet5.so` even for KDE Frameworks 6 / Plasma 6.** There is no `pam_kwallet6.so`. The "5" in the name is a legacy artifact. The previous discovery note incorrectly stated `pam_kwallet6.so` would be provided — this was wrong.
- [fact] The existing `/etc/pam.d/sddm` and `/etc/pam.d/sddm-autologin` files already reference `pam_kwallet5.so` — they just need the package installed; **no module name changes are needed**.
## (2) PAM configuration
### Plasma 6 / ksecretd consideration
The Arch Wiki (section "Configure PAM on Plasma 6 (KF6)", updated 2026-03-10) says Plasma 6 uses `ksecretd` as the secret service daemon. The PAM session line should include `kwalletd=/usr/bin/ksecretd` to point to the new daemon.
- [fact] `ksecretd` binary is at `/usr/bin/ksecretd` and is shipped by the `kwallet` package (6.23.0-1)
- [fact] `kwalletd6` binary is at `/usr/bin/kwalletd6` and is also in the `kwallet` package
- [decision] For a non-Plasma Hyprland setup, the question is which daemon to target. The Arch Wiki recommends `kwalletd=/usr/bin/ksecretd` for KF6. Since the user has `kwalletd6` and `ksecretd` both installed via the `kwallet` package, and the Arch Wiki explicitly documents this parameter for KF6, the documentation should use the `kwalletd=/usr/bin/ksecretd` parameter.
### Recommended `/etc/pam.d/sddm` (password login)
The file already has the right structure. After installing `kwallet-pam`, the existing lines become functional. However, for Plasma 6 / KF6 compatibility, the session line should add the `kwalletd=` parameter:
```
#%PAM-1.0
auth sufficient pam_u2f.so cue
auth include system-login
-auth optional pam_gnome_keyring.so
-auth optional pam_kwallet5.so
account include system-login
password include system-login
session optional pam_keyinit.so force revoke
session include system-login
-session optional pam_gnome_keyring.so auto_start
-session optional pam_kwallet5.so auto_start kwalletd=/usr/bin/ksecretd
```
Key points:
- [fact] The `-` prefix on `-auth` and `-session` lines means "skip silently if module is missing" — this is already present in the default SDDM PAM files
- [fact] The `auth` line captures the user password for later use by the session line
- [fact] The `session` line with `auto_start` tells the module to start kwalletd/ksecretd and unlock the wallet
- [fact] `kwalletd=/usr/bin/ksecretd` directs the module to use KF6's ksecretd daemon instead of the legacy kwalletd5
### Recommended `/etc/pam.d/sddm-autologin`
This file is for SDDM autologin ONLY. Since the chosen model is password login, this file is informational but should still be kept correct:
```
#%PAM-1.0
auth sufficient pam_u2f.so cue
auth required pam_permit.so
-auth optional pam_kwallet5.so
account include system-local-login
password include system-local-login
session include system-local-login
-session optional pam_kwallet5.so auto_start kwalletd=/usr/bin/ksecretd
```
- [caveat] Autologin skips password entry → PAM has no password to pass to `pam_kwallet5.so` → wallet cannot be unlocked unless LUKS passphrase forwarding is used (see section 5)
### Minimal edit needed for existing system
Since the existing `/etc/pam.d/sddm` already has `pam_kwallet5.so` lines, the only change needed is:
1. Install `kwallet-pam` (makes the module file appear at `/usr/lib/security/pam_kwallet5.so`)
2. Add `kwalletd=/usr/bin/ksecretd` to the session line for KF6 compatibility
The auth line does NOT need the `kwalletd=` parameter — only the session line does.
## (3) Wallet initialization for non-Plasma (Hyprland) users
### Step A: Create the wallet
The wallet **must** be named `kdewallet` (the default name). PAM unlock only works with this specific wallet name.
**Option 1 — GUI (recommended if kwalletmanager is available):**
```bash
sudo pacman -S kwalletmanager
kwalletmanager6
```
Then: File > New Wallet > name it `kdewallet` > set password to match login password > choose **blowfish** encryption (NOT GPG).
**Option 2 — Headless/CLI:**
No pure-CLI wallet creation tool exists. The wallet is created automatically when:
1. The PAM module is installed and configured
2. The user logs in via SDDM with password
3. `pam_kwallet_init` runs and kwalletd6/ksecretd starts
4. If no wallet exists, kwalletd6 creates one on first access
For a truly headless init, trigger it by running in the session:
```bash
# Ensure kwalletd6/ksecretd is running (D-Bus activated)
dbus-send --session --dest=org.kde.kwalletd6 --print-reply \
/modules/kwalletd6 org.kde.KWallet.open \
string:"kdewallet" int64:0 string:"init"
```
This prompts for the wallet password interactively (Qt dialog).
### Step B: Ensure wallet password matches login password
- [requirement] The KWallet password MUST be identical to the Unix user login password. PAM passes the login password to the kwallet module; if they differ, the wallet won't unlock.
- [requirement] If the user password is changed later, the wallet password must be updated to match. Use `kwalletmanager6` > Change Password, or delete and recreate the wallet.
### Step C: kwalletrc configuration
Create `~/.config/kwalletrc` if it doesn't exist:
```ini
[Wallet]
Default Wallet=kdewallet
Enabled=true
First Use=false
[org.freedesktop.secrets]
apiEnabled=true
```
The `apiEnabled=true` setting enables the org.freedesktop.secrets D-Bus API, allowing libsecret-based apps (Chromium, VSCode, etc.) to use KWallet.
### Step D: Autostart `pam_kwallet_init` in Hyprland
The `kwallet-pam` package installs an XDG autostart entry (`/etc/xdg/autostart/pam_kwallet_init.desktop`), but Hyprland does NOT process XDG autostart files by default.
Add to `~/.config/hypr/hyprland.conf`:
```
exec-once = /usr/lib/pam_kwallet_init
```
This script reads the PAM-cached credentials and passes them to kwalletd6/ksecretd to unlock the wallet.
### Step E: D-Bus activation service (optional but recommended)
Create `~/.local/share/dbus-1/services/org.freedesktop.secrets.service`:
```ini
[D-BUS Service]
Name=org.freedesktop.secrets
Exec=/usr/bin/kwalletd6
```
This ensures kwalletd6 auto-starts when any app requests secrets via D-Bus, even before the wallet is explicitly opened.
## (4) Verification
### Quick verification after login
```bash
# 1. Check the PAM module is installed
ls -la /usr/lib/security/pam_kwallet5.so
# 2. Check kwalletd6 or ksecretd is running
pgrep -a kwalletd6 || pgrep -a ksecretd
# 3. Check the wallet is open
dbus-send --session --dest=org.kde.kwalletd6 --print-reply \
/modules/kwalletd6 org.kde.KWallet.isOpen \
string:"kdewallet"
# 4. Check wallet files exist
ls -la ~/.local/share/kwalletd/
# 5. Query the wallet (should return without prompting for password)
kwallet-query -l kdewallet
# 6. Check environment variables set by pam_kwallet_init
echo $PAM_KWALLET5_LOGIN
```
### Full integration test
1. Log out of Hyprland
2. At SDDM greeter, type user password and log in
3. After Hyprland starts, run `kwallet-query -l kdewallet` — it should list folders without prompting
4. Open a KWallet-aware app (e.g., Chromium with `--password-store=kwallet5`) and verify it stores/retrieves credentials
### Troubleshooting if wallet doesn't auto-unlock
- Check `journalctl --user -u plasma-kwallet-pam.service` for errors
- Check `journalctl -b | grep -i kwallet` for PAM-level errors
- Verify wallet password matches login password exactly
- Verify wallet is named exactly `kdewallet` (not `default` or any other name)
- Verify wallet uses blowfish encryption, not GPG
## (5) Caveats
### U2F / pam_u2f.so interaction
- [risk] The existing `/etc/pam.d/sddm` has `auth sufficient pam_u2f.so cue` as the FIRST auth line. When `sufficient` succeeds, PAM skips remaining auth modules — including `pam_kwallet5.so`.
- [consequence] If the user authenticates via U2F key only (no password typed), the kwallet module never captures a password → wallet cannot be unlocked automatically.
- [mitigation] This is acceptable if U2F is used as a convenience shortcut and the user accepts that wallet won't auto-unlock in that case. The wallet can be manually unlocked later.
- [alternative] To make U2F + kwallet work together, change `sufficient` to a two-factor setup where password is always required. But this changes the security model and is out of scope for this documentation.
### Autologin caveat
- [risk] SDDM autologin (`pam_permit.so`) provides no password → `pam_kwallet5.so` has nothing to unlock the wallet with.
- [fact] The Arch Wiki documents a workaround using `pam_systemd_loadkey.so` for LUKS-encrypted systems: the LUKS passphrase can be forwarded from the initramfs to the PAM stack, allowing wallet unlock even with autologin.
- [requirement] This requires: (1) systemd-based initramfs (`sd-encrypt` hook, not classic `encrypt`), (2) `pam_systemd_loadkey.so` line in sddm-autologin, (3) sddm.service override with `KeyringMode=inherit`.
- [fact] The current system uses classic `encrypt` hook, NOT `sd-encrypt`, so this workaround is NOT available without migrating the initramfs to systemd hooks.
- [decision] Since password login (not autologin) was chosen, this is informational only.
### Fingerprint reader caveat
- [fact] KWallet cannot be unlocked using a fingerprint reader (per Arch Wiki). Similar to U2F — no password is available.
### GPG encryption caveat
- [fact] `kwallet-pam` does NOT work with GPG-encrypted wallets. The wallet MUST use standard blowfish encryption.
### hyprlock caveat
- [fact] hyprlock uses `auth include login` in `/etc/pam.d/hyprlock`. The login PAM chain does NOT include kwallet PAM modules. Unlocking hyprlock will NOT re-open the wallet if it was closed.
- [mitigation] Typically the wallet stays open for the session duration. If the wallet is configured with `Leave Open=true` (in kwalletrc or kwalletmanager), it won't close automatically.
### Password change caveat
- [fact] If the user's login password is changed (via `passwd`), the wallet password must be manually updated to match. PAM does not automatically synchronize wallet passwords on password change.
## Relations
- related_to [[LUKS SDDM KWallet discovery]]
- related_to [[luks-sddm-kwallet-login-integration]]
- related_to [[LUKS SDDM KWallet documentation targets]]