#include "ipc.h"
#include "logging.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/utsname.h>
#include <time.h>
#include <unistd.h>
#include <errno.h>

ipc_mailbox_t *g_shm_mailbox = NULL;
int g_ipc_notify_pipe = -1;

void setup_ipc(void) {
    g_shm_mailbox = mmap(NULL, sizeof(ipc_mailbox_t), 
                         PROT_READ | PROT_WRITE, 
                         MAP_SHARED | MAP_ANONYMOUS, -1, 0);

    if (g_shm_mailbox == MAP_FAILED) {
        LOG_CRIT("Failed to allocate shared memory mailbox (%s)", strerror(errno));
        _exit(EXIT_FAILURE);
    }
}

void sandbox_send(ipc_message_t *msg, size_t msg_len) {
    if (!g_shm_mailbox || g_ipc_notify_pipe == -1) 
        _exit(EXIT_FAILURE);

    // Wait until supervisor is ready to receive a new message
    while (g_shm_mailbox->is_ready == 1)
        __asm__ volatile("pause");

    // Load message into shared memory
    memcpy(&g_shm_mailbox->message, msg, msg_len);
    g_shm_mailbox->is_ready = 1;

    // Notify the supervisor
    char signal_byte = 1;
    if (write(g_ipc_notify_pipe, &signal_byte, 1) != 1) {
        _exit(EXIT_FAILURE);
    }
}

// --- Supervisor Logic ---
void handle_ipc_command(ipc_message_t *msg) {
    switch (msg->command) {
        case CMD_SYSTEM:
            LOG_CRIT("system('%s') attempted /!\\", msg->data.system.path);
            break;
        case CMD_EXECVE:
            LOG_CRIT("execve('%s') attempted /!\\", msg->data.execve.path);
            break;
        case CMD_OPEN:
            LOG_CRIT("open('%s', %d) attempted /!\\", msg->data.open.path, msg->data.open.flags);
            break;
        case CMD_POPEN:
            LOG_CRIT("popen('%s') attempted /!\\", msg->data.popen.path);
            break;
        case CMD_CHMOD:
            LOG_CRIT("chmod('%s', %d) attempted /!\\", msg->data.chmod.path, msg->data.chmod.mode);
            break;
        
        case CMD_UNAME: {
            // Malwares are using uname to fingerprint the kernel version
            // Let's fool them !!
            struct utsname *u = &msg->data.uname.buf;
            strncpy(u->sysname, "Linux", sizeof(u->sysname) - 1);
            strncpy(u->nodename, "sandbox", sizeof(u->nodename) - 1);
            strncpy(u->release, "5.15.0-sandbox", sizeof(u->release) - 1);
            strncpy(u->version, "#1 SMP Sandbox", sizeof(u->version) - 1);
            strncpy(u->machine, "x86_64", sizeof(u->machine) - 1);
            break;
        }
        case CMD_GETRANDOM: {
            // Ransomwares may use getrandom to generate keys
            // Let's make the randomness deterministic so I can recover my files
            size_t request_len = msg->data.getrandom.buflen;
            size_t max_len = sizeof(msg->data.getrandom.buf);
            if (request_len > max_len) request_len = max_len;

            // Fill with deterministic randomness
            unsigned char *buf = (unsigned char *)(msg->data.getrandom.buf);
            for (size_t i = 0; i < request_len; i++) {
                buf[i] = rand() % 256;
            }
            msg->data.getrandom.buflen = request_len;
            break;
        }
        case CMD_UNLINK: {
            LOG_CRIT("unlink('%s') attempted !", msg->data.unlink.path);
            break;
        }
        default:
            LOG_CRIT("Command not supported. This should never happen!");
            break;
    }
}
