#!/usr/bin/env bash
#
# Wazuh 5.0 agent connectivity triage, run ON THE ENDPOINT (Linux or macOS).
#
# Every Wazuh-specific command below comes from the Wazuh 5.0-beta
# documentation. The script only collects evidence; it changes nothing.
#
#   Usage: sudo ./check-agent-connection.sh <MANAGER_IP_OR_FQDN>
#
# Lesson: https://maheshtata.com/wazuh/wazuh-agent-disconnected/

set -u

MANAGER="${1:-}"
if [ -z "$MANAGER" ]; then
    echo "Usage: $0 <MANAGER_IP_OR_FQDN>" >&2
    exit 2
fi

# Agent install prefix: /var/ossec on Linux and Unix, /Library/Ossec on macOS.
if [ -d /Library/Ossec ]; then
    PREFIX=/Library/Ossec
else
    PREFIX=/var/ossec
fi

rule() { printf '\n== %s ==\n' "$1"; }

rule "1. Agent connection state"
# Documented values: connected, pending, disconnected.
grep '^status' "$PREFIX/var/run/wazuh-agentd.state" 2>/dev/null \
    || echo "state file not found at $PREFIX/var/run/wazuh-agentd.state"

rule "2. Agent daemons"
"$PREFIX/bin/wazuh-control" status 2>&1

rule "3. Agent version"
"$PREFIX/bin/wazuh-control" info -v 2>&1

rule "4. Configured manager endpoint"
# 5.0 uses <agent><manager><endpoint>. A 4.x file uses <client><server>.
grep -E '<endpoint>|<address>|<groups>|<agent_name>' "$PREFIX/etc/ossec.conf" 2>/dev/null \
    || echo "no endpoint/groups settings found in $PREFIX/etc/ossec.conf"

rule "5. Enrolment password file present?"
if [ -f "$PREFIX/etc/authd.pass" ]; then
    ls -l "$PREFIX/etc/authd.pass"      # expect 640, owner root
else
    echo "absent: the manager rejects enrolment when use_password is yes"
fi

rule "6. Agent key present?"
if [ -f "$PREFIX/etc/client.keys" ]; then
    # Print the id, name and ip columns only. The key itself stays hidden.
    awk '{print $1, $2, $3}' "$PREFIX/etc/client.keys"
else
    echo "absent: the agent has not enrolled yet"
fi

rule "7. Port reachability (1517 for a 5.0 agent, 55000 for API enrolment)"
if command -v nc >/dev/null 2>&1; then
    nc -zv "$MANAGER" 1517 55000
else
    echo "netcat not installed; skipping"
fi

rule "8. HTTPS listener liveness probe"
# Verified on Wazuh 5.0.0-beta5 (23 Sep 2026):
#   https://MANAGER:1517/                -> {"error":"not_found"}
#   https://MANAGER:1517/wazuh-manager/  -> {"status":"ok","module":"remoted"}
# The prefix comes from <remote><https><global_prefix>, which ships as
# /wazuh-manager/. A probe against the root looks like a dead listener and is
# not; override API_PREFIX only if your own wazuh-manager.conf differs.
API_PREFIX="${API_PREFIX:-/wazuh-manager/}"
curl -sk --max-time 10 "https://$MANAGER:1517${API_PREFIX}" ; echo
echo "(healthy: {\"status\":\"ok\",\"module\":\"remoted\"}; a root probe returns {\"error\":\"not_found\"} even when healthy)"

rule "9. Clock"
# Each request carries a JWT with a 60s lifetime and roughly 30s of tolerated
# skew, so a drifted endpoint clock breaks authentication with a generic 401.
date -u

rule "10. Last 40 agent log lines"
# Two verified enrolment rejections to look for (both leave the state 'pending'):
#   ERROR: Enrollment rejected by the manager: invalid or missing
#          authentication. Invalid client authentication   -> wrong authd.pass
#   ERROR: Enrollment rejected by the manager: invalid request.
#          Invalid Group(s) Name(s)                        -> group not on manager
# A successful enrolment logs: INFO: Valid key received
tail -n 40 "$PREFIX/logs/ossec.log" 2>/dev/null \
    || echo "no log at $PREFIX/logs/ossec.log"

printf '\nManager-side checks to run next, on the manager:\n'
printf '  /var/wazuh-manager/bin/wazuh-manager-control status   # expect 8 daemons on beta5, monitord included\n'
printf '  tail -n 100 /var/wazuh-manager/logs/wazuh-manager.log # "Invalid group:" names the group; nothing here means a password rejection\n'
printf '  grep -A8 "<https>" /var/wazuh-manager/etc/wazuh-manager.conf\n'
printf '  /var/wazuh-manager/bin/agent_groups -l                # the group must exist BEFORE the agent enrols\n'
