#!/bin/sh
# SecuBox Auth Logger - RPCD plugin for LuCI authentication logging
# Copyright (C) 2024 CyberMind.fr
#
# This plugin wraps session.login to log authentication failures
# for CrowdSec detection.

. /lib/functions.sh
. /usr/share/libubox/jshn.sh

LOG_FILE="/var/log/secubox-auth.log"
LOG_TAG="secubox-auth"

# Ensure log file exists
[ -f "$LOG_FILE" ] || { touch "$LOG_FILE"; chmod 644 "$LOG_FILE"; }

# Log authentication failure
log_auth_failure() {
    local ip="$1"
    local user="${2:-root}"
    local service="${3:-luci}"

    # Get timestamp in syslog format
    local ts=$(date "+%b %d %H:%M:%S")
    local hostname=$(cat /proc/sys/kernel/hostname 2>/dev/null || echo "OpenWrt")

    # Log to dedicated file for CrowdSec
    echo "$ts $hostname $LOG_TAG[$$]: authentication failure for $user from $ip via $service" >> "$LOG_FILE"

    # Also log to syslog for visibility
    logger -t "$LOG_TAG" -p auth.warning "authentication failure for $user from $ip via $service"
}

# Get client IP from environment or connection info
get_client_ip() {
    # Try various methods to get client IP

    # Method 1: REMOTE_ADDR (if called via CGI)
    [ -n "$REMOTE_ADDR" ] && echo "$REMOTE_ADDR" && return

    # Method 2: HTTP_X_FORWARDED_FOR (if behind proxy)
    [ -n "$HTTP_X_FORWARDED_FOR" ] && echo "${HTTP_X_FORWARDED_FOR%%,*}" && return

    # Method 3: Parse from uhttpd connection (not available in rpcd context)
    # Method 4: Default to local if unknown
    echo "127.0.0.1"
}

# Perform login via ubus and return result
do_login() {
    local username="$1"
    local password="$2"
    local client_ip="$3"

    # Call the real session.login via ubus
    local result
    result=$(ubus call session login "{\"username\":\"$username\",\"password\":\"$password\"}" 2>&1)
    local rc=$?

    if [ $rc -ne 0 ] || echo "$result" | grep -q '"ubus_rpc_session": ""' || echo "$result" | grep -qi "error\|denied"; then
        # Login failed - log it
        log_auth_failure "$client_ip" "$username" "luci"

        # Return failure
        json_init
        json_add_boolean success 0
        json_add_string error "Login failed"
        json_add_string ip "$client_ip"
        json_dump
    else
        # Login succeeded - return the session token
        echo "$result"
    fi
}

case "$1" in
    list)
        # List available methods
        cat <<'EOF'
{
    "wrapped_login": {
        "username": "str",
        "password": "str",
        "client_ip": "str"
    },
    "log_failure": {
        "ip": "str",
        "username": "str",
        "service": "str"
    },
    "get_client_info": {}
}
EOF
        ;;
    call)
        case "$2" in
            wrapped_login)
                # Parse JSON input
                read -r input
                json_load "$input"
                json_get_var username username
                json_get_var password password
                json_get_var client_ip client_ip

                # Use provided IP or try to detect
                [ -z "$client_ip" ] && client_ip=$(get_client_ip)

                # Perform login with logging
                do_login "$username" "$password" "$client_ip"
                ;;

            log_failure)
                # Direct logging method for JS to call
                read -r input
                json_load "$input"
                json_get_var ip ip
                json_get_var username username
                json_get_var service service

                [ -z "$ip" ] && ip="unknown"
                [ -z "$username" ] && username="root"
                [ -z "$service" ] && service="luci"

                log_auth_failure "$ip" "$username" "$service"

                json_init
                json_add_boolean success 1
                json_add_string message "Auth failure logged for $ip"
                json_dump
                ;;

            get_client_info)
                # Return whatever client info we can detect
                local ip=$(get_client_ip)

                json_init
                json_add_string ip "$ip"
                json_add_string remote_addr "${REMOTE_ADDR:-unknown}"
                json_dump
                ;;
        esac
        ;;
esac
