#!/bin/bash
# svctrap — Hardened canary/trap system
set -euo pipefail
shopt -s inherit_errexit 2>/dev/null || true
IFS=$'\n\t'

readonly NODE_ID="${NODE_ID:-}"
readonly ENGINE_IP="${ENGINE_IP:-10.69.69.6}"
readonly VAULT_KEY_FILE="${VAULT_KEY_FILE:-/dev/shm/vault.key}"
readonly CANARY_STATE="/run/se/state/canary"
readonly LOG_DIR="/run/se/logs"
readonly CONF="/run/se/.nodeconf"
readonly CANARY_FILES="${CANARY_FILES:-/etc/.sshd_config.bak /etc/.nginx.conf.bak /var/.backup.tar.gz /home/.profile.bak}"
readonly CANARY_PORTS="${CANARY_PORTS:-4444 5555 6666}"
readonly LOCK_FILE="/run/se/.svctrap.lock"

if [[ -z "${NODE_ID}" ]]; then printf 'ERR: NODE_ID not set\n' >&2; exit 1; fi

exec 300>"${LOCK_FILE}"
if ! flock -n 300; then printf 'ERR: svctrap already running\n' >&2; exit 1; fi

t003_loadconf() {
    if [[ -f "${CONF}" ]]; then
        local perms
        perms="$(stat -c '%a' "${CONF}" 2>/dev/null || printf '%s' '000')"
        [[ "${perms}" == "600" || "${perms}" == "400" ]] && source "${CONF}"
    fi
}

t003_log() {
    local m="${1:-}"
    logger -t "canary-${NODE_ID}" "${m}" 2>/dev/null || true
    mkdir -p "${LOG_DIR}"
    printf '%s %s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "${m}" >> "${LOG_DIR}/canary.log"
}

t003_report() {
    local ev="${1:-}"
    local ts n p s
    ts="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
    n="$(openssl rand -hex 16)"
    p="${ts}:${n}:${NODE_ID}"
    if [[ -f "${VAULT_KEY_FILE}" ]]; then
        s="$(printf '%s' "${p}" | openssl dgst -sha256 -hmac "$(cat "${VAULT_KEY_FILE}")" | awk '{print $2}')"
    else
        s='none'
    fi
    curl -sf --connect-timeout 3 --max-time 10 \
        -X POST "http://${ENGINE_IP}:8301/a/security/event" \
        -H 'Content-Type: application/json' \
        -d "{\"node\":\"${NODE_ID}\",\"event\":\"${ev}\",\"sig\":\"${ts}:${n}:${s}\"}" \
        2>/dev/null || true
}

# ── Plant canaries — NO fake credential patterns ───────────────────────────
t003_plant() {
    t003_loadconf
    mkdir -p /run/se/state
    local f
    for f in ${CANARY_FILES}; do
        if [[ ! -f "${f}" ]]; then
            # Use non-credential patterns to avoid false security scanner alerts
            printf '# Canary file - DO NOT MODIFY - node=%s\n' "${NODE_ID}" >"${f}"
            printf 'config_version=canary-v4.0.0\n' >>"${f}"
            printf 'generated_at=%s\n' "$(date -u +%s)" >>"${f}"
            printf 'marker=%s\n' "$(openssl rand -hex 32)" >>"${f}"
            chmod 644 "${f}"
        fi
    done
    # Start canary listeners on ports
    local p
    for p in ${CANARY_PORTS}; do
        if ! ss -tln | grep -q ":${p} "; then
            (ncat -lkp "${p}" -e /bin/false &) 2>/dev/null || true
        fi
    done
    t003_log 'canaries planted'
    printf '%s' 'planted' >"${CANARY_STATE}.status"
}

t003_monitor() {
    t003_loadconf
    local trg=0 h h0 f p c
    for f in ${CANARY_FILES}; do
        if [[ -f "${f}" ]]; then
            h="$(sha256sum "${f}" | awk '{print $1}')"
            h0="$(cat "${CANARY_STATE}.${f//\//_}.hash" 2>/dev/null || printf '%s' '')"
            if [[ -n "${h0}" && "${h}" != "${h0}" ]]; then
                t003_log "canary touched: ${f}"
                t003_report "canary-trip:${f}"
                trg=1
            fi
        fi
    done
    for p in ${CANARY_PORTS}; do
        c="$(ss -tln | grep -c ":${p} " || printf '%s' '0')"
        if [[ "${c}" -gt 1 ]]; then
            t003_log "canary port probed: ${p}"
            t003_report "canary-probe:${p}"
            trg=1
        fi
    done
    if journalctl -n 50 --no-pager 2>/dev/null | grep -qi 'canary\|honeypot\|trap\|fake'; then
        trg=1
    fi
    if [[ "${trg}" -eq 1 ]]; then
        t003_log 'canary triggered'
    fi
}

t003_savehash() {
    local f
    for f in ${CANARY_FILES}; do
        if [[ -f "${f}" ]]; then
            sha256sum "${f}" | awk '{print $1}' >"${CANARY_STATE}.${f//\//_}.hash"
        fi
    done
}

t003_cleanup() {
    local f
    for f in ${CANARY_FILES}; do
        rm -f "${f}"
    done
    pkill -f 'ncat.*-lkp' 2>/dev/null || true
    printf '%s' 'cleaned' >"${CANARY_STATE}.status"
    t003_log 'canaries cleaned'
}

t003_init() {
    mkdir -p "${LOG_DIR}" "$(dirname "${CANARY_STATE}")"
    t003_plant
    t003_savehash
    t003_log 'canary init'
}

t003_start() {
    (
        while true; do
            t003_monitor
            sleep 20
        done
    ) &
    printf '%s' "$!" >"${CANARY_STATE}.pid"
    t003_log 'canary monitor started'
}

t003_stop() {
    if [[ -f "${CANARY_STATE}.pid" ]]; then
        local pid
        pid="$(cat "${CANARY_STATE}.pid")"
        if kill -0 "${pid}" 2>/dev/null; then
            kill "${pid}" 2>/dev/null || true
            wait "${pid}" 2>/dev/null || true
        fi
        rm -f "${CANARY_STATE}.pid"
    fi
    t003_log 'canary monitor stopped'
}

t003_status() {
    if [[ -f "${CANARY_STATE}.pid" ]]; then
        local pid
        pid="$(cat "${CANARY_STATE}.pid")"
        if kill -0 "${pid}" 2>/dev/null; then
            printf '%s\n' 'running'
        else
            printf '%s\n' 'stopped'
        fi
    else
        printf '%s\n' 'stopped'
    fi
    cat "${CANARY_STATE}.status" 2>/dev/null || printf '%s\n' 'unknown'
}

t003_run() {
    t003_plant
    t003_monitor
}

cleanup_trap() { flock -u 300 2>/dev/null || true; }
trap cleanup_trap EXIT

case "${1:-}" in
    init)   t003_init ;;
    start)  t003_start ;;
    stop)   t003_stop ;;
    status) t003_status ;;
    run)    t003_run ;;
    *)      printf 'usage: %s init|start|stop|status|run\n' "$0"; exit 1 ;;
esac
