NoSignal-OS/os updates/caelestia-lock-faillock/patch-lock-pam.sh
28allday 19fd794b6b NoSignal — fully-offline Arch → Hyprland desktop installer
Single-script builder (nosignal.sh) that turns a stock Arch Linux ISO into a
fully-offline installer for a themed Hyprland + caelestia (Quickshell) desktop:
matching SDDM greeter, Btrfs/Limine bootable snapshots, chwd-style GPU
detection, and a curated "os updates" layer (keybind cheatsheet, settings
panels, system polish, on-box management skill). See README.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 11:03:10 +01:00

72 lines
3.3 KiB
Bash
Executable file

#!/bin/sh
# patch-lock-pam.sh — make the Caelestia lock screen use a faillock-free PAM
# service. Two parts, both idempotent:
#
# 1. DELIVER the faillock-free `caelestia` service into the directory the lock
# actually reads — Quickshell.shellDir + "/assets/pam.d" — i.e.
# /etc/xdg/quickshell/caelestia/assets/pam.d/caelestia. (Placing it in
# /etc/pam.d/caelestia, which PamContext never reads, makes the lock
# fall through to assets/pam.d/passwd — still faillock'd — and reject even
# the correct password.)
# 2. REPOINT the lock's PamContext at it: config: "passwd" -> "caelestia".
#
# Runs as root (via the installer, or the pacman hook after every caelestia-shell
# upgrade, which restores the shell tree under /etc/xdg — so BOTH the asset file
# and the repoint must be re-applied here each time, or an upgrade drops them).
#
# Symptom (before this fix): the lock screen rejects the CORRECT password; only a
# reboot escapes. The stock lock authenticates via PamContext { config: "passwd",
# configDirectory: shellDir + "/assets/pam.d" } -> assets/pam.d/passwd, which
# calls pam_faillock; a few failed unlocks trip a temporary account lock that
# then refuses every attempt (right password included) until /run/faillock clears.
#
# TARGET (Pam.qml) is overridable for testing the change against a copy; the
# asset destination is derived from it (shellDir = TARGET/../../..).
set -eu
HERE=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
SRC_PAM="$HERE/etc-pam.d-caelestia" # the faillock-free service we ship
TARGET=${TARGET:-/etc/xdg/quickshell/caelestia/modules/lock/Pam.qml}
[ -f "$TARGET" ] || { echo "caelestia-shell lock not found at $TARGET — nothing to patch"; exit 0; }
# shellDir = the caelestia shell root = three levels up from modules/lock/Pam.qml.
SHELLDIR=$(CDPATH= cd -- "$(dirname -- "$TARGET")/../.." && pwd)
ASSETS_PAMD="$SHELLDIR/assets/pam.d"
# --- 1. deliver the faillock-free service where the lock reads it -------------
if [ -f "$SRC_PAM" ]; then
install -d -m 0755 "$ASSETS_PAMD"
install -m 0644 "$SRC_PAM" "$ASSETS_PAMD/caelestia"
echo ":: installed $ASSETS_PAMD/caelestia (faillock-free lock auth)"
else
echo "WARNING: source PAM service $SRC_PAM missing — cannot deliver the lock service." >&2
fi
# --- 2. repoint the lock's PamContext at it ----------------------------------
# Already pointed at our service?
if grep -q 'config:[[:space:]]*"caelestia"' "$TARGET"; then
echo ":: Pam.qml already points at the caelestia lock service"
exit 0
fi
# Only act if the stock "passwd" service is referenced.
if ! grep -q 'config:[[:space:]]*"passwd"' "$TARGET"; then
echo "WARNING: Pam.qml does not reference config: \"passwd\" — upstream shape changed." >&2
echo " Leaving it untouched; review the lock PamContext for the new" >&2
echo " service name and update the regex in $(basename "$0")." >&2
exit 0
fi
cp -n "$TARGET" "$TARGET.pre-nosignal" 2>/dev/null || true
# Repoint only the PAM service name; keep everything else as-is.
sed -i 's/config:\([[:space:]]*\)"passwd"/config:\1"caelestia"/g' "$TARGET"
if grep -q 'config:[[:space:]]*"caelestia"' "$TARGET"; then
echo ":: patched $TARGET (lock now uses the faillock-free caelestia PAM service)"
else
echo "WARNING: patch did not apply — Pam.qml left untouched." >&2
exit 0
fi