fix(ansipa): fix ansipa-fetch-alerts.sh alert delivery and acknowledgment
Three bugs fixed, all confirmed end-to-end in a live FreeIPA + client VM: 1. Wrong `who` column: loginctl is SESSION/UID/USER (col 3), but `who` is USER/TTY/DATE (col 1) — the fallback used col 3, delivering to the wrong user. Split into _parse_session_user() with per-source column selection. 2. Delivered to all users: alerts were sent to every active non-root session instead of only members of usr_scan-notify. Added `id -nG` group check inside _parse_session_user(). 3. smbclient ls path breakage: `smbclient -c "ls alerts\host\"` treats the argument as a glob pattern, returning NT_STATUS_NO_SUCH_FILE. Changed to `cd alerts\host; ls` which correctly lists directory contents. Bonus: track ACKNOWLEDGED set so alerts deleted-from-server in the current run are not re-downloaded (avoiding a spurious WARN on the same run). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DHops6PU4c2Mv5UyhUj8Msfeat/astal-menu
parent
65e859b8f9
commit
00ce4f5260
|
|
@ -46,26 +46,51 @@ touch "$FETCHED_STATE"
|
|||
|
||||
smb() { smbclient "//$IPA_SERVER/$SMB_SHARE" -A "$CREDS_FILE" "$@" 2>/dev/null; }
|
||||
|
||||
# ── List active login sessions ────────────────────────────────────────────────
|
||||
# ── List active login sessions (usr_scan-notify members only) ─────────────────
|
||||
# loginctl list-sessions --no-legend: SESSION UID USER SEAT TTY → $3 = USER
|
||||
# who: USER TTY DATE TIME (HOST) → $1 = USER
|
||||
# Only deliver to members of the usr_scan-notify FreeIPA user group.
|
||||
ACTIVE_USERS=()
|
||||
_parse_session_user() {
|
||||
local line="$1" src="$2"
|
||||
local user
|
||||
if [[ "$src" == "loginctl" ]]; then
|
||||
user=$(awk '{print $3}' <<< "$line")
|
||||
else
|
||||
user=$(awk '{print $1}' <<< "$line")
|
||||
fi
|
||||
[[ -z "$user" || "$user" == "root" || "$user" == "USER" ]] && return
|
||||
# Only deliver to members of usr_scan-notify.
|
||||
id -nG "$user" 2>/dev/null | tr ' ' '\n' | grep -qxF "usr_scan-notify" || return
|
||||
local home
|
||||
home=$(getent passwd "$user" | cut -d: -f6 2>/dev/null) || return
|
||||
[[ -d "$home" ]] && ACTIVE_USERS+=("$user:$home")
|
||||
}
|
||||
|
||||
if loginctl list-sessions --no-legend &>/dev/null; then
|
||||
while IFS= read -r LINE; do
|
||||
USER=$(echo "$LINE" | awk '{print $3}')
|
||||
[[ -z "$USER" || "$USER" == "root" ]] && continue
|
||||
HOME_DIR=$(getent passwd "$USER" | cut -d: -f6) || continue
|
||||
[[ -d "$HOME_DIR" ]] && ACTIVE_USERS+=("$USER:$HOME_DIR")
|
||||
done < <(loginctl list-sessions --no-legend 2>/dev/null || who 2>/dev/null || true)
|
||||
_parse_session_user "$LINE" "loginctl"
|
||||
done < <(loginctl list-sessions --no-legend 2>/dev/null)
|
||||
else
|
||||
while IFS= read -r LINE; do
|
||||
_parse_session_user "$LINE" "who"
|
||||
done < <(who 2>/dev/null)
|
||||
fi
|
||||
# Deduplicate by user.
|
||||
mapfile -t ACTIVE_USERS < <(printf '%s\n' "${ACTIVE_USERS[@]}" | sort -u)
|
||||
mapfile -t ACTIVE_USERS < <(printf '%s\n' "${ACTIVE_USERS[@]+"${ACTIVE_USERS[@]}"}" | sort -u)
|
||||
|
||||
# ── List alerts on server for this host ───────────────────────────────────────
|
||||
# smbclient `ls path\` treats the argument as a pattern, not a cd target;
|
||||
# use `cd path; ls` to list directory contents instead.
|
||||
SERVER_ALERTS=()
|
||||
while IFS= read -r LINE; do
|
||||
# smbclient ls output: " filename.alert A 1234 date"
|
||||
FILE=$(echo "$LINE" | awk '{print $1}')
|
||||
FILE=$(awk '{print $1}' <<< "$LINE")
|
||||
[[ "$FILE" == *.alert ]] && SERVER_ALERTS+=("$FILE")
|
||||
done < <(smb -c "ls alerts\\$HOSTNAME\\" 2>/dev/null || true)
|
||||
done < <(smb -c "cd alerts\\$HOSTNAME; ls" 2>/dev/null || true)
|
||||
|
||||
# ── Check for locally deleted alerts (acknowledged) ───────────────────────────
|
||||
ACKNOWLEDGED=()
|
||||
while IFS= read -r ALERT_NAME; do
|
||||
[[ -z "$ALERT_NAME" ]] && continue
|
||||
# If none of the active users still have this alert file, it was acknowledged.
|
||||
|
|
@ -82,8 +107,9 @@ while IFS= read -r ALERT_NAME; do
|
|||
if [[ "$ALL_DELETED" == true ]] && [[ ${#ACTIVE_USERS[@]} -gt 0 ]]; then
|
||||
log "Alert acknowledged (deleted locally): $ALERT_NAME — removing from server"
|
||||
smb -c "del alerts\\$HOSTNAME\\$ALERT_NAME" 2>/dev/null || true
|
||||
# Remove from state file.
|
||||
# Remove from state file and skip re-download in this run.
|
||||
sed -i "/^$ALERT_NAME\$/d" "$FETCHED_STATE" 2>/dev/null || true
|
||||
ACKNOWLEDGED+=("$ALERT_NAME")
|
||||
fi
|
||||
done < "$FETCHED_STATE"
|
||||
|
||||
|
|
@ -92,6 +118,9 @@ TMP_DIR=$(mktemp -d /tmp/ansipa-alerts.XXXXXX)
|
|||
trap 'rm -rf "$TMP_DIR"' EXIT
|
||||
|
||||
for ALERT_NAME in "${SERVER_ALERTS[@]}"; do
|
||||
# Skip alerts already acknowledged (and deleted from server) in this run.
|
||||
[[ " ${ACKNOWLEDGED[*]+"${ACKNOWLEDGED[*]}"} " == *" $ALERT_NAME "* ]] && continue
|
||||
|
||||
TMP_FILE="$TMP_DIR/$ALERT_NAME"
|
||||
|
||||
# Download alert content from server.
|
||||
|
|
|
|||
Loading…
Reference in New Issue