Compare commits
No commits in common. "88f3b7234381c640c82973201364080317a96991" and "d35d6d17d652d5839f3f8ccc16744790f5884dd2" have entirely different histories.
88f3b72343
...
d35d6d17d6
|
|
@ -14,10 +14,7 @@ PYTHON_DETECT="$SCRIPT_DIR/python/presence_detect.py"
|
||||||
# Both factors required, with the normal password stack kept as a fallback so a
|
# Both factors required, with the normal password stack kept as a fallback so a
|
||||||
# dead camera or absent key can never lock you out.
|
# dead camera or absent key can never lock you out.
|
||||||
PAM_TARGETS=(/etc/pam.d/sudo /etc/pam.d/hyprlock /etc/pam.d/login)
|
PAM_TARGETS=(/etc/pam.d/sudo /etc/pam.d/hyprlock /etc/pam.d/login)
|
||||||
# howdy 2.x has no pam_howdy.so — it authenticates through pam_python.so loading
|
PAM_HOWDY_SO="/usr/lib/security/pam_howdy.so"
|
||||||
# its own entrypoint script. pam_python.so ships in the AUR package `pam-python`.
|
|
||||||
PAM_PYTHON_SO="/usr/lib/security/pam_python.so"
|
|
||||||
HOWDY_PAM_PY="/usr/lib/security/howdy/pam.py"
|
|
||||||
PAM_U2F_SO="/usr/lib/security/pam_u2f.so"
|
PAM_U2F_SO="/usr/lib/security/pam_u2f.so"
|
||||||
U2F_MAP="/etc/u2f_mappings"
|
U2F_MAP="/etc/u2f_mappings"
|
||||||
PAM_MARK_BEGIN="# enroll-biometrics:begin howdy+u2f 2fa"
|
PAM_MARK_BEGIN="# enroll-biometrics:begin howdy+u2f 2fa"
|
||||||
|
|
@ -146,16 +143,7 @@ presence_test_camera() {
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Howdy helpers ─────────────────────────────────────────────────────────────
|
# ── Howdy helpers ─────────────────────────────────────────────────────────────
|
||||||
# Detection must survive howdy 2.x's layout: its CLI lives under root-only
|
howdy_installed() { command -v howdy &>/dev/null; }
|
||||||
# /usr/lib/security/howdy/ with /usr/bin/howdy symlinked into it, so a normal
|
|
||||||
# user can neither resolve nor run the link — `command -v howdy` reports "not
|
|
||||||
# found" even when it is installed. Every op here invokes it via `sudo howdy`
|
|
||||||
# anyway, so fall back to the symlink itself and the package DB.
|
|
||||||
howdy_installed() {
|
|
||||||
command -v howdy &>/dev/null && return 0
|
|
||||||
[[ -L /usr/bin/howdy || -e /usr/bin/howdy ]] && return 0
|
|
||||||
command -v pacman &>/dev/null && pacman -Qq howdy &>/dev/null
|
|
||||||
}
|
|
||||||
|
|
||||||
howdy_require() {
|
howdy_require() {
|
||||||
howdy_installed && return 0
|
howdy_installed && return 0
|
||||||
|
|
@ -255,42 +243,6 @@ howdy_test() {
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── howdy PAM module (pam_python.so) ──────────────────────────────────────────
|
|
||||||
# howdy's PAM entrypoint is a Python script loaded by pam_python.so. The module
|
|
||||||
# is /usr/lib/security/pam_python.so directly (world-traversable, unlike howdy's
|
|
||||||
# own root-only dir), so a plain existence test is reliable here; pacman -Qq is
|
|
||||||
# the fallback in case it lands elsewhere.
|
|
||||||
pam_python_installed() {
|
|
||||||
[[ -e "$PAM_PYTHON_SO" ]] && return 0
|
|
||||||
command -v pacman &>/dev/null && pacman -Qq pam-python &>/dev/null
|
|
||||||
}
|
|
||||||
|
|
||||||
pam_python_require() {
|
|
||||||
pam_python_installed && return 0
|
|
||||||
|
|
||||||
# pam-python is AUR-only, so it needs an AUR helper just like howdy.
|
|
||||||
local helper
|
|
||||||
for h in yay paru; do
|
|
||||||
command -v "$h" &>/dev/null && { helper="$h"; break; }
|
|
||||||
done
|
|
||||||
if [[ -z "$helper" ]]; then
|
|
||||||
msg "No AUR Helper" \
|
|
||||||
"howdy's PAM module needs the AUR package 'pam-python', which requires an AUR helper (yay or paru).\n\nInstall yay first, then re-run." \
|
|
||||||
11 62
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
dialog --backtitle "$BACKTITLE" --title " pam-python Needed " \
|
|
||||||
--yesno "\nhowdy authenticates via pam_python.so, provided by the AUR package 'pam-python'.\n\nInstall it now via ${helper}?" 10 62 || return 1
|
|
||||||
clear
|
|
||||||
printf "\nInstalling pam-python via %s...\n\n" "$helper"
|
|
||||||
"$helper" -S --noconfirm --needed pam-python
|
|
||||||
pam_python_installed || {
|
|
||||||
msg "Install Failed" "pam-python installation failed.\nInstall it manually: ${helper} -S pam-python" 8 58
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# ── FIDO U2F helpers ────────────────────────────────────────────────────────────
|
# ── FIDO U2F helpers ────────────────────────────────────────────────────────────
|
||||||
fido_installed() { [[ -e "$PAM_U2F_SO" ]] && command -v pamu2fcfg &>/dev/null; }
|
fido_installed() { [[ -e "$PAM_U2F_SO" ]] && command -v pamu2fcfg &>/dev/null; }
|
||||||
|
|
||||||
|
|
@ -339,7 +291,7 @@ fido_register() {
|
||||||
# existing (password) auth lines below.
|
# existing (password) auth lines below.
|
||||||
pam_emit_block() {
|
pam_emit_block() {
|
||||||
printf '%s\n' "$PAM_MARK_BEGIN"
|
printf '%s\n' "$PAM_MARK_BEGIN"
|
||||||
printf 'auth [success=ignore default=1] pam_python.so %s\n' "$HOWDY_PAM_PY"
|
printf 'auth [success=ignore default=1] pam_howdy.so\n'
|
||||||
printf 'auth sufficient pam_u2f.so authfile=%s cue\n' "$U2F_MAP"
|
printf 'auth sufficient pam_u2f.so authfile=%s cue\n' "$U2F_MAP"
|
||||||
printf '%s\n' "$PAM_MARK_END"
|
printf '%s\n' "$PAM_MARK_END"
|
||||||
}
|
}
|
||||||
|
|
@ -411,9 +363,13 @@ pam_remove_hyprlock() {
|
||||||
|
|
||||||
pam_setup() {
|
pam_setup() {
|
||||||
howdy_require || return
|
howdy_require || return
|
||||||
pam_python_require || return
|
|
||||||
fido_require || return
|
fido_require || return
|
||||||
|
|
||||||
|
if [[ ! -e "$PAM_HOWDY_SO" ]]; then
|
||||||
|
msg "Missing PAM Module" "pam_howdy.so not found at:\n$PAM_HOWDY_SO\n\nReinstall howdy and try again." 10 60
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
dialog --backtitle "$BACKTITLE" --title " Set Up PAM 2FA " --yesno \
|
dialog --backtitle "$BACKTITLE" --title " Set Up PAM 2FA " --yesno \
|
||||||
"\nThis will require BOTH face (howdy) and a FIDO key for:\n\n ${PAM_TARGETS[*]}\n\nYour password still works if a factor is unavailable.\nBackups of each file are saved as *.bak.<timestamp>.\n\nContinue?" 15 64 || return
|
"\nThis will require BOTH face (howdy) and a FIDO key for:\n\n ${PAM_TARGETS[*]}\n\nYour password still works if a factor is unavailable.\nBackups of each file are saved as *.bak.<timestamp>.\n\nContinue?" 15 64 || return
|
||||||
|
|
||||||
|
|
|
||||||
21
sysupdate.sh
21
sysupdate.sh
|
|
@ -616,30 +616,15 @@ sync_configs() {
|
||||||
[[ "$skip" == true ]] && continue
|
[[ "$skip" == true ]] && continue
|
||||||
|
|
||||||
if [[ "$name" == "hypr" ]]; then
|
if [[ "$name" == "hypr" ]]; then
|
||||||
# Copy hypr/ contents but preserve ~/.config/hypr/usr/.
|
# Copy hypr/ contents but preserve ~/.config/hypr/usr/
|
||||||
# Stage each item into a temp dir on the same filesystem, then mv it
|
|
||||||
# into place — for files this is an atomic rename(2), so Hyprland's
|
|
||||||
# live config watcher never sees hyprland.lua momentarily missing
|
|
||||||
# (which otherwise makes it emit its fallback hyprland.conf stub).
|
|
||||||
mkdir -p "$target/hypr"
|
mkdir -p "$target/hypr"
|
||||||
local hypr_ok=true
|
local hypr_ok=true
|
||||||
local stage; stage="$(mktemp -d "${target}/hypr/.sync.XXXXXX")" || hypr_ok=false
|
|
||||||
if $hypr_ok; then
|
|
||||||
while IFS= read -r -d '' hitem; do
|
while IFS= read -r -d '' hitem; do
|
||||||
local hname; hname="$(basename "$hitem")"
|
local hname; hname="$(basename "$hitem")"
|
||||||
[[ "$hname" == "usr" ]] && continue
|
[[ "$hname" == "usr" ]] && continue
|
||||||
if cp -r "$hitem" "$stage/"; then
|
rm -rf "${target}/hypr/${hname}" && cp -r "$hitem" "$target/hypr/" \
|
||||||
# mv can't atomically replace a non-empty dir, so clear
|
|| hypr_ok=false
|
||||||
# an existing directory target first; files swap atomically.
|
|
||||||
[[ -d "$stage/$hname" && -d "${target}/hypr/${hname}" ]] \
|
|
||||||
&& rm -rf "${target}/hypr/${hname}"
|
|
||||||
mv -f "$stage/$hname" "${target}/hypr/${hname}" || hypr_ok=false
|
|
||||||
else
|
|
||||||
hypr_ok=false
|
|
||||||
fi
|
|
||||||
done < <(find "$item" -maxdepth 1 -mindepth 1 -print0 | sort -z)
|
done < <(find "$item" -maxdepth 1 -mindepth 1 -print0 | sort -z)
|
||||||
rm -rf "$stage"
|
|
||||||
fi
|
|
||||||
if $hypr_ok; then
|
if $hypr_ok; then
|
||||||
ok "synced hypr ${DI}(usr/ preserved)${RS}"
|
ok "synced hypr ${DI}(usr/ preserved)${RS}"
|
||||||
(( synced++ )) || true
|
(( synced++ )) || true
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue