#!/bin/sh
# sandbox-handler — executa handler de conector isolado em namespaces.
#
# Protecoes principais contra codigo de terceiros:
#   - monta namespace privado para nao propagar mounts para o host;
#   - esconde espaco/ de todos os sistemas sob a raiz SISC;
#   - esconde secretos/ de todos os sistemas e core/biblioteca-secretos;
#   - reexpoe somente secretos/<conector>.json do sistema atual, somente leitura;
#   - entrega ao handler uma copia somente-leitura da mensagem.
#
# Uso: sandbox-handler <sistema> <conector> <arquivo-mensagem> <handler> [args...]

set -eu

if [ "$#" -lt 4 ]; then
    echo "sandbox-handler: uso: sandbox-handler <sistema> <conector> <arquivo-mensagem> <handler> [args...]" >&2
    exit 64
fi

SISTEMA=$1
CONECTOR=$2
MENSAGEM=$3
HANDLER=$4
shift 4

case "$CONECTOR" in
    ''|*[!A-Za-z0-9_-]*|*..*)
        echo "sandbox-handler: conector invalido" >&2
        exit 64
        ;;
esac

case "$HANDLER" in
    "$SISTEMA"/conectores/"$CONECTOR"/handlers/*) ;;
    *)
        echo "sandbox-handler: handler fora de conectores/$CONECTOR/handlers" >&2
        exit 78
        ;;
esac

[ -d "$SISTEMA" ] || { echo "sandbox-handler: sistema inexistente" >&2; exit 78; }
[ -f "$MENSAGEM" ] || { echo "sandbox-handler: mensagem inexistente" >&2; exit 66; }
[ -f "$HANDLER" ] && [ -x "$HANDLER" ] || { echo "sandbox-handler: handler ausente/sem execucao" >&2; exit 78; }

RAIZ=$(dirname "$SISTEMA")
TMP=$(mktemp -d "${TMPDIR:-/tmp}/sisc-sandbox-XXXXXX") || exit 70
chmod 0700 "$TMP"
trap 'rm -rf "$TMP"' EXIT INT TERM

cp "$MENSAGEM" "$TMP/mensagem.json" || exit 66
chmod 0444 "$TMP/mensagem.json"

SECRET="$SISTEMA/secretos/$CONECTOR.json"
if [ -f "$SECRET" ]; then
    cp "$SECRET" "$TMP/$CONECTOR.json" || exit 74
    chmod 0444 "$TMP/$CONECTOR.json"
fi

cd "$SISTEMA" || exit 78

unshare --user --map-root-user --mount --fork -- sh -c '
    set -eu
    SISTEMA=$1; RAIZ=$2; CONECTOR=$3; TMP=$4; HANDLER=$5; shift 5

    ocultar_dir() {
        d=$1
        [ -d "$d" ] || return 0
        [ ! -L "$d" ] || return 78
        mount -t tmpfs -o nosuid,nodev,noexec none "$d"
    }

    # Impede que os mounts do sandbox vazem para o namespace do host.
    mount --make-rprivate /

    # Esconde barramentos de mensagens de todos os sistemas conhecidos.
    ocultar_dir "$SISTEMA/espaco"
    for d in "$RAIZ"/*/espaco; do [ -e "$d" ] && ocultar_dir "$d"; done

    # Esconde todos os segredos locais/sistêmicos acessiveis por caminho previsivel.
    ocultar_dir "$RAIZ/secretos"
    ocultar_dir "$RAIZ/core/biblioteca-secretos"
    ocultar_dir "$SISTEMA/secretos"
    for d in "$RAIZ"/*/secretos; do [ -e "$d" ] && ocultar_dir "$d"; done

    # Reexpoe somente o segredo do proprio conector no sistema atual.
    if [ -f "$TMP/$CONECTOR.json" ]; then
        mkdir -p "$SISTEMA/secretos"
        touch "$SISTEMA/secretos/$CONECTOR.json"
        chmod 0600 "$SISTEMA/secretos/$CONECTOR.json"
        mount --bind "$TMP/$CONECTOR.json" "$SISTEMA/secretos/$CONECTOR.json"
        mount -o remount,ro,bind "$SISTEMA/secretos/$CONECTOR.json"
    fi

    exec "$HANDLER" "$TMP/mensagem.json" "$@"
' sh "$SISTEMA" "$RAIZ" "$CONECTOR" "$TMP" "$HANDLER" "$@"
