diff --git a/setup/modules/FreeipaAnsible/ansible/ansipa-fetch-alerts.sh b/setup/modules/FreeipaAnsible/ansible/ansipa-fetch-alerts.sh index 66b23c5..50da0d7 100644 --- a/setup/modules/FreeipaAnsible/ansible/ansipa-fetch-alerts.sh +++ b/setup/modules/FreeipaAnsible/ansible/ansipa-fetch-alerts.sh @@ -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=() -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() { + 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 + _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.