#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <pwd.h>
#include <grp.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <termios.h>

#include "config.h"

#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif


#ifdef PTYS_ARE_PTMX
# include <sys/resource.h>	/* for struct rlimit */
# include <sys/stropts.h>	/* for I_PUSH */
# define _NEW_TTY_CTRL		/* to get proper defines in <termios.h> */
#endif


#define MAX_TIMEOUT 240

/* #define DEBUG */

#ifndef FALSE
#define FALSE (0)
#endif
#ifndef TRUE
#define TRUE (!FALSE)
#endif

#ifndef IGNORE
#define IGNORE  1
#endif
#ifndef SAVE
#define SAVE    2
#endif
#ifndef RESTORE
#define RESTORE 3
#endif

#ifndef O_NDELAY
#define O_NDELAY O_NONBLOCK
#endif

extern char password[128];
extern char passphrase[128];
extern char * hom_str;
extern void print_dbg (const char *fmt, ...);
extern void get_pw();
extern void get_pp();
extern void privileges(int mode);

extern pid_t child_pid;
extern int   opt_tarflag;

static char    *ttydev = NULL;	/* pty/tty name */
static struct stat ttyfd_stat;	/* original status of the tty we will use */
static short    changettyowner = 1;

/* ssh reads the password not from stdin, but from /dev/tty
 * therefore, we put the subprocess on a virtual console (what a pain ...)
 */

/* the following two subroutines are from rxvt
 */

/*{{{ Acquire a pseudo-teletype from the system. */
/*
 * On failure, returns -1.
 * On success, returns the file descriptor.
 *
 * If successful, ttydev and ptydev point to the names of the
 * master and slave parts
 */
/* INTPROTO */
static int
get_pty(void)
{
    int             fd;
    char           *ptydev;

#ifdef PTYS_ARE__GETPTY
    if ((ptydev = ttydev = _getpty(&fd, O_RDWR | O_NDELAY, 0622, 0)) != NULL)
	goto Found;
#endif
#ifdef PTYS_ARE_GETPTY
    while ((ptydev = getpty()) != NULL)
	if ((fd = open(ptydev, O_RDWR)) >= 0) {
	   ttydev = ptydev;
	   goto Found;
	}
#endif
#if defined(HAVE_GRANTPT) && defined(HAVE_UNLOCKPT)
# if defined(PTYS_ARE_GETPT) || defined(PTYS_ARE_PTMX)
    {
        /*@i@*/ extern char    *ptsname();

#  ifdef PTYS_ARE_GETPT
	/*@-unrecog@*/
	if ((fd = getpt()) >= 0) {
	  /*@+unrecog@*/
#  else
	if ((fd = open("/dev/ptmx", O_RDWR)) >= 0) {
#  endif
	    if (grantpt(fd) == 0 	/* change slave permissions */
		&& unlockpt(fd) == 0) {	/* slave now unlocked */
		ptydev = ttydev = ptsname(fd);	/* get slave's name */
		changettyowner = 0;
		goto Found;
	    }
	    close(fd);
	}
    }
# endif
#endif
#ifdef PTYS_ARE_PTC
    if ((fd = open("/dev/ptc", O_RDWR)) >= 0) {
	ptydev = ttydev = ttyname(fd);
	goto Found;
    }
#endif
#ifdef PTYS_ARE_CLONE
    if ((fd = open("/dev/ptym/clone", O_RDWR)) >= 0) {
	ptydev = ttydev = ptsname(fd);
	goto Found;
    }
#endif
#ifdef PTYS_ARE_NUMERIC
    {
	int             idx;
	char           *c1, *c2;
	char            pty_name[] = "/dev/ptyp???";
	char            tty_name[] = "/dev/ttyp???";

	ptydev = pty_name;
	ttydev = tty_name;

	c1 = &(pty_name[sizeof(pty_name) - 4]);
	c2 = &(tty_name[sizeof(tty_name) - 4]);
	for (idx = 0; idx < 256; idx++) {
	    sprintf(c1, "%d", idx);
	    sprintf(c2, "%d", idx);
	    if (access(ttydev, F_OK) < 0) {
		idx = 256;
		break;
	    }
	    if ((fd = open(ptydev, O_RDWR)) >= 0) {
		if (access(ttydev, R_OK | W_OK) == 0) {
		    ttydev = strdup(tty_name);
		    goto Found;
		}
		close(fd);
	    }
	}
    }
#endif
#ifdef PTYS_ARE_SEARCHED
    {
	size_t          len;
	const char     *c1, *c2;
	char            pty_name[] = "/dev/pty??";
	char            tty_name[] = "/dev/tty??";

	len = sizeof(pty_name) - 3;
	ptydev = pty_name;
	ttydev = tty_name;

# define PTYCHAR1	"pqrstuvwxyz"
# define PTYCHAR2	"0123456789abcdef"
	for (c1 = PTYCHAR1; *c1; c1++) {
	    ptydev[len] = ttydev[len] = *c1;
	    for (c2 = PTYCHAR2; *c2; c2++) {
		ptydev[len + 1] = ttydev[len + 1] = *c2;
		fd = open(ptydev, O_RDWR);
		/* fprintf(stderr, "%s %s %d\n", ttydev, ptydev, fd); */
	        if (fd >= 0) {
		    if (access(ttydev, R_OK | W_OK) == 0) {
			ttydev = strdup(tty_name);
			goto Found;
		    }
		    close(fd);
		}
	    }
	}
    }
#endif

    print_dbg("can't open pseudo-tty");
    return -1;

  Found:
    fcntl(fd, F_SETFL, O_NDELAY);
    return fd;
}
/*}}} */

/*{{{ establish a controlling teletype for new session */
/*
 * On some systems this can be done with ioctl() but on others we
 * need to re-open the slave tty.
 */
/* INTPROTO */
static int
get_tty(void)
{
    int             fd, i;
    pid_t           pid;

/*
 * setsid() [or setpgrp] must be before open of the terminal,
 * otherwise there is no controlling terminal (Solaris 2.4, HP-UX 9)
 */
#ifndef ultrix
# ifdef NO_SETSID
    pid = setpgrp(0, 0);
# else
    pid = setsid();
# endif
    if (pid < 0)
	perror("get_tty: setsid: ");

# ifdef DEBUG_TTYMODE
    print_dbg("(%s: line %d): PID = %d\n", __FILE__, __LINE__, pid);
# endif

#endif				/* ultrix */

    if ((fd = open(ttydev, O_RDWR)) < 0
       && (fd = open("/dev/tty", O_RDWR)) < 0) { 
	print_dbg("can't open slave tty %s", ttydev);
	exit(EXIT_FAILURE);
    }

#ifdef PTYS_ARE_PTMX
/*
 * Push STREAMS modules:
 *    ptem: pseudo-terminal hardware emulation module.
 *    ldterm: standard terminal line discipline.
 *    ttcompat: V7, 4BSD and XENIX STREAMS compatibility module.
 */
    if (!changettyowner) {
	ioctl(fd, I_PUSH, "ptem");
	ioctl(fd, I_PUSH, "ldterm");
#if !defined(sgi) && !defined(__sgi)
	ioctl(fd, I_PUSH, "ttcompat");
#endif
    }
#endif
    if (changettyowner) {
    /* change ownership of tty to real uid and real group */
	unsigned int    mode = 0622;
	gid_t           gid = getgid();

#ifdef TTY_GID_SUPPORT
	{
	    struct group   *gr = getgrnam("tty");

	    if (gr) {
	    /* change ownership of tty to real uid, "tty" gid */
		gid = gr->gr_gid;
		mode = 0620;
	    }
	}
#endif				/* TTY_GID_SUPPORT */
#ifndef __CYGWIN32__
	{

	  privileges(RESTORE);
	  i = fchown(fd, getuid(), gid);
	  /*
	  fprintf(stderr, "fchown fd=%d uid=%d, gid=%d, res=%d\n",
		  fd, (int) getuid(), (int) gid, i);
	  */
	  i = fchmod(fd, mode);
	  /*
	  fprintf(stderr, "fchmod fd=%d res=%d\n", fd, i);
	  */
	  privileges(IGNORE);

	}
#endif
    }

/*
 * Close all file descriptors.  If only stdin/out/err are closed,
 * child processes remain alive upon deletion of the window.
 */
    /*
    for (i = 3; i < 256; i++)
	if (i != fd)
	    close(i);
    */

/* Reopen stdin, stdout and stderr over the tty file descriptor */
    dup2(fd, 0);		/* stdin */
#ifdef OPEN_SSH_D
    dup2(fd, 1); 		/* stdout */ /* TRY */
    dup2(fd, 2); 		/* stderr */ /* TRY */
#endif

    if (fd > 2)
	close(fd);

#ifdef ultrix
    if ((fd = open("/dev/tty", O_RDONLY)) >= 0) {
      ioctl(fd, /*@i@*/ TIOCNOTTY, 0);
	close(fd);
    } else {
	pid = setpgrp(0, 0);
	if (pid < 0)
	    perror("get_tty: setpgrp: ");
    }

/* no error, we could run with no tty to begin with */
#else				/* ultrix */
# ifdef TIOCSCTTY
    ioctl(0, /*@i@*/ TIOCSCTTY, 0);
# endif

/* set process group */
# if defined (_POSIX_VERSION) || defined (__svr4__)
    tcsetpgrp(0, pid);
# elif defined (TIOCSPGRP)
    ioctl(0, /*@i@*/ TIOCSPGRP, &pid);
# endif

/* svr4 problems: reports no tty, no job control */
/* # if !defined (__svr4__) && defined (TIOCSPGRP) */
    close(open(ttydev, O_RDWR, 0));
/* # endif */
#endif				/* ultrix */

    return fd;
}
/*}}} */



static void restore_tty (char * slave)
{
  /* fail silently if unprivileged
   */
  privileges (RESTORE);
  chmod(slave, ttyfd_stat.st_mode);
  chown(slave, ttyfd_stat.st_uid, ttyfd_stat.st_gid);
  privileges (IGNORE);

  return;
}
  

static int errflag = 0;


/* Read the ssh subprocess response. Braindead ssh expects password
 * from /dev/tty, and does not fallback on stdin.
 * Even more braindead: OpenSSH **PRINTS** the password prompt to /dev/tty !!
 */
static char * fdgets (char * buf, int size, int fd, int fderr
#ifdef OPEN_SSH
	       , int fdmaster
#endif
	       )
{

  fd_set             my_set;
  struct timeval     tv;

  char             *  p;

  int                countbytes;
  ssize_t            count;

  int                select_now;
  int                num_sel;
  int                num_err;
  
  int                status;
  long               exstat;
  int                maxnum;

  errflag      = 0;

  countbytes   = 0;
  select_now   = 0;
  tv.tv_sec    = 1;
  tv.tv_usec   = 0;

  buf[0]       = '\0';
  p            = buf;

  if (fd > fderr) 
    maxnum = fd;
  else 
    maxnum = fderr;


#ifdef OPEN_SSH
  if (maxnum > fdmaster) 
    maxnum = maxnum;
  else 
    maxnum = fdmaster;
#endif

  while ( countbytes < (size - 2)) {

    FD_ZERO(&my_set);
    FD_SET(fd, &my_set);
    FD_SET(fderr, &my_set);
#ifdef OPEN_SSH
    FD_SET(fdmaster, &my_set);
#endif

    if ( (num_sel = select (maxnum+1, &my_set, NULL, NULL, &tv)) == -1) 
      {
	if ( errno == EINTR ) /* try again */
	  continue;
	num_err = errno;
	fprintf (stderr, "Error in select(): %s\n", strerror(num_err));
	buf[countbytes] = '\0';
	return NULL;
      }

    /* on Linux, timeout is modified
     */
    tv.tv_sec   = 1;
    tv.tv_usec  = 0;

#ifdef DEBUG
    fprintf (stderr, "SE: %d selected.\n", num_sel);
#endif


    if (num_sel == 0) /* timeout */
      {
	if (NULL != strstr (buf, "password: ") )
	  {
	    buf[countbytes] = '\0';
	    return buf;
	  }
	if (NULL != strstr (buf, "Enter passphrase") )
	  {
	    buf[countbytes] = '\0';
	    return buf;
	  }
	if (NULL != strstr (buf, "(yes/no)? ") )
	  {
	    buf[countbytes] = '\0';
	    return buf;
	  }

	++select_now;      
	if ( select_now > MAX_TIMEOUT )
	  {
	    fprintf (stderr, "Timeout after %d seconds.\n", MAX_TIMEOUT);
	    buf[countbytes] = '\0';
	    if (countbytes == 0)
	      return NULL;
	    else
	      return buf;
	  }
      }
    
    if ( FD_ISSET (fd, &my_set))
      {
	count = read  (fd, p, 1);     /* --- READ --- */

	if (count > 0) 
	  {
	    countbytes += count;
#ifdef DEBUG
	    fprintf (stderr, "S-: |%c|\n", p);
#endif
	    if (*p == '\n')            /* newline, return */
	      {
		buf[countbytes] = '\0';
		return buf;
	      }

	    p          += count;       /* move buffer pointer forward */
	    FD_SET( fd,    &my_set );
	  }

	else if (count < 0)
	  {
	    num_err = errno;
	    if (0 < (exstat = (long) waitpid (child_pid, 
					       &status, WNOHANG|WUNTRACED)))
	      {
		/* Child has exited. Check exit value. 
		 */
		child_pid = 0;
		if (WIFEXITED(status) != 0 && 0 != WEXITSTATUS(status))
		  fprintf (stderr, "return code: %d\n",
			  WEXITSTATUS(status));
	      }
	    else
	      {
		fprintf (stderr, 
			 "Error reading from pipe: %s\n", 
			 strerror(num_err));
	      }
	    buf[countbytes] = '\0';
	    return NULL;
	  }

	else /* count == 0; broken pipe -> */
	  {
	    num_err = errno;
	    buf[countbytes] = '\0';
	    /* Child has exited. Check exit value. 
	     */
	    if (0 < waitpid (child_pid, &status, WNOHANG|WUNTRACED))
	      {
		if (WIFEXITED(status) != 0 && 0 != WEXITSTATUS(status))
		  fprintf (stderr, "return code: %d\n",
			  WEXITSTATUS(status));
	      }
	    child_pid = 0;
	    return NULL;
	  }

      }
  
    if ( FD_ISSET (fderr, &my_set) 
#ifdef OPEN_SSH
	 || FD_ISSET (fdmaster, &my_set)
#endif
	 )
      {
#ifdef OPEN_SSH
	if (FD_ISSET (fdmaster, &my_set)) 
	  count = read  (fdmaster, p, 1);
	else
#endif
	  count = read  (fderr, p, 1);     /* --- READ --- */

#ifdef DEBUG
	fprintf (stderr, "E-: |%c|\n", p);
#endif
	if (count > 0) 
	  {
	    countbytes += count;

	    if (*p == '\n')            /* newline, return */
	      {
		buf[countbytes] = '\0';
		errflag = 1;
		return buf;
	      }

	    p          += count;       /* move buffer pointer forward */
	    FD_SET( fderr, &my_set );
	  }

	else if (count < 0)
	  {
	    num_err = errno;
	    /* Child has exited. Check exit value. 
	     */
	    if (0 < (exstat = (long) waitpid (child_pid, 
					      &status, WNOHANG|WUNTRACED)))
	      {
		if (WIFEXITED(status) != 0 && 0 != WEXITSTATUS(status))
		  fprintf (stderr, "return code: %d\n",
			  WEXITSTATUS(status));
	      }
	    else
	      {
		fprintf (stderr, 
			 "Error reading from pipe: %s\n", 
			 strerror(num_err));
	      }
	    buf[countbytes] = '\0';
	    errflag = 1;
	    return NULL;
	  }

	else /* count == 0; broken pipe -> */
	  {
	    ;  /* do nothing */
	  }
      }
  }

  buf[countbytes] = '\0';
  return buf;
}



static int user_handler(int mode, int master, 
			int input_pipe[], int output_pipe[], 
			int inerr_pipe[])
{

  ssize_t rc;         /* return values of functions. */
  char    line[256];
  char *  p;
  char    c;
  int     i = 0;


  /* first, close unnecessary file descriptors 
   */
  close ( input_pipe[1]); /* we don't need to write to this pipe.  */
  close ( inerr_pipe[1]); /* we don't need to write to this pipe.  */
  close (output_pipe[0]); /* we don't need to read from this pipe. */
  
  fcntl (input_pipe[0],  F_SETFL, O_NONBLOCK);
  fcntl (inerr_pipe[0],  F_SETFL, O_NONBLOCK);
  
  /* loop: read input, send via one pipe, read via other */
  /* pipe, and write to stdout. exit on EOF from user.   */
  
  while ( NULL != fdgets (line, 256, input_pipe[0], inerr_pipe[0]
#ifdef OPEN_SSH
			  , master
#endif
			  ) ) 
    {
	
#ifdef DEBUG
      print_dbg ("line in: [%d] <%s> \n", strlen(line), line);
#endif
      
      if (NULL != strstr (line, "password: ") )
	{
	  /* 'master' is the controlling terminal for
	   *  the spawned subprocess that runs ssh
	   */
	  if (password[0] == '\0')
	    {
	      get_pw();
	    }
	  rc = write(master, password, strlen(password));
	  rc += write(master, "\n", 1);
	  if (rc <= -1) 
	    { 
	      perror("user_handler: write");
	      close(input_pipe[0]);
	      close(output_pipe[1]);
	      memset (password, 0, 128);
	      memset (passphrase, 0, 128);
	      return -2;
	    }
	  print_dbg ("Password sent: %d bytes.", rc-1);
	  continue;
	}
      
      if (NULL != strstr (line, "Enter passphrase") )
	{
	  /* 'master' is the controlling terminal for
	   *  the spawned subprocess that runs ssh
	   */
	  if (passphrase[0] == '\0')
	    {
	      get_pp(line);
	    }
	  rc = write(master, passphrase, strlen(passphrase));
	  rc = write(master, "\n", 1);
	  if (rc == -1) 
	    { 
	      perror("user_handler: write");
	      close(input_pipe[0]);
	      close(output_pipe[1]);
	      memset (password, 0, 128);
	      memset (passphrase, 0, 128);
	      return -2;
	    }
	  print_dbg ("Using passphrase to unlock private key.");
	  continue;
	}
      
      if (NULL != strstr (line, "(yes/no)? ") )
	{
	  /* 'master' is the controlling terminal for
	   *  the spawned subprocess that runs ssh
	   */
	  rc = write(master, "yes", 3);
	  rc = write(master, "\n", 1);
	  if (rc == -1) 
	    { 
	      perror("user_handler: write");
	      close(input_pipe[0]);
	      close(output_pipe[1]);
	      memset (password, 0, 128);
	      memset (passphrase, 0, 128);
	      return -2;
	    }
	  print_dbg ("Login confirmation sent.");
	  continue;
	}
      
      if (errflag == 0 && mode == 0)
	{
	  strncpy(hom_str, line, 256);
	  hom_str[255] = '\0';
	  p = &hom_str[strlen(hom_str)-1];
	  while (*p == ' ' || *p == '\n') *p = '\0';
	  print_dbg ("Received path of home directory <%s>", hom_str);
	  close(input_pipe[0]);
	  close(inerr_pipe[0]);
	  close(output_pipe[1]);
	  close(master);
	  return 0;
	}
      
      if (errflag == 1 && line[0] != '\n')
	{
#ifdef OPEN_SSH
	  if (strlen(line) == 2)
	    continue;
#endif
	  if (line[strlen(line)-1] == '\n')
	    fprintf(stderr, "%s", line);
	  else
	    fprintf(stderr, "%s\n", line);
	  
	  /* Permission denied.
	   */
	  if (NULL != strstr (line, "Permission denied"))
	    {
	      memset (password, 0, 128);
	      memset (passphrase, 0, 128);
	      exit (EXIT_FAILURE);
	    }
	  
	  /* stty thingy
	   */
	  if (NULL != strstr (line, "stty:"))
	    continue;
	  
	  /* more fun
	   */
	  if (NULL != strstr (line, "Trying"))
	    continue;
	  
	  /* more fun
	   */
	  if (NULL != strstr (line, "Logging in"))
	    continue;
	  
	  /* bad passphrase
	   */
	  if (NULL != strstr (line, "Bad passphrase"))
	    continue;
	  
	  /* new seed 
	   */
	  if (NULL != strstr (line, "Creating random seed file"))
	    continue;
	  
	  /* blurb 
	   */
	  if (NULL != strstr (line, "Received signal"))
	    continue;
	  
	  /* blurb 
	   */
	  if (NULL != strstr (line, "OpenSSH") && 
	      NULL != strstr (line, "SSH protocols"))
	    continue;
	  
	  /* new host
	   */
	  if (NULL != strstr (line, "list of known hosts"))
	    continue;
	  
	  
	  /* tar
	   */
	  if (NULL != strstr (line, "tar: B: unknown option"))
	    {
	      opt_tarflag = FALSE;
	      close(input_pipe[0]);
	      close(inerr_pipe[0]);
	      close(output_pipe[1]);
	      close(master);
	      return -1;
	    }
	  
	  /* some other error
	   */
	  fprintf(stderr, "Continue (Y/n) ? ");
	  while (1 == 1) 
	    {
	      c = getc(stdin);
	      if (c == 'Y' || c == 'y' || c == '\n') 
		break;
	      else if (c == 'N' || c == 'n') {
		close(input_pipe[0]);
		close(inerr_pipe[0]);
		close(output_pipe[1]);
		close(master);
		return -2;
	      }
	      else {
		fprintf(stderr, "Continue (Y/n) ? ");
	      }
	    }
	  continue;
	}
      

      if (errflag == 0 && mode == 1)
	{
	  p = &line[strlen(line)-1];
	  while (*p) { if (*p == '\n') *p = '\0'; --p; }
	  if (line[strlen(line)-1] == ':')
	    { printf("\n\n%s\n", line); }
	  else if (strlen(line) > 40)
	    { printf("%s\n", line); }
	  else
	    { 
	      printf("%s", line); 
	      if (strlen(line) < 8) 
		printf("\t\t\t");
	      else if (strlen(line) < 16)
		printf("\t\t");
	      else
		printf("\t");
	      ++i;
	      if (i == 3) { fputc('\n', stdout); i = 0; }
	    }
	  continue;
	}
      
      /* default
       */
      if (errflag == 0) 
	fprintf(stdout, "%s", line);
      
    }
  
  if (mode == 1)
    fputc('\n', stdout);
  
  /* close pipes and exit. 
   */
  close(input_pipe[0]);
  close(inerr_pipe[0]);
  close(output_pipe[1]);
  close(master);
  
  return 0;
}

/* now comes the function executed by the translator process. */
static void translator(char * command, int input_pipe[], int output_pipe[], 
		       int outerr_pipe[])
{

#ifdef DEBUG_P
  char blah[256]; 
#endif

  /* first, close unnecessary file descriptors 
   */
  close ( input_pipe[1]); /* we don't need to write to this pipe.  */
  close (output_pipe[0]); /* we don't need to read from this pipe. */
  close (outerr_pipe[0]); /* we don't need to read from this pipe. */
  
  fcntl (input_pipe[0],  F_SETFL, O_NONBLOCK);
  
  dup2(outerr_pipe[1],  STDERR_FILENO );
  dup2(output_pipe[1],  STDOUT_FILENO );
#ifdef OPEN_SSH_D
  dup2( input_pipe[0],   STDIN_FILENO ); /* TRY */ 
#endif
  
#ifdef DEBUG_P
  fputs ("password: ", stdout);
  fflush (stdout);
  fputs (fgets(blah, 255, stdin), stdout);
#endif
  
  execl("/bin/sh", "sh", "-c", command, NULL);
  
  fflush(stdout); sleep(1);
  
  _exit (127);
}

/* spawn off the subprocess to run ssh 
 */
int piper (char * command, int mode)
{
   int master;
   int slave;   /* slave pty */

   int retval = 0;

    /* 2 arrays to contain file descriptors, for two pipes. 
     */
    int user_to_translator[2];
    int translator_to_user[2];
    int err_to_user[2];

    pid_t pid;       /* pid of child process, or 0 in parent thread. */
    int   rc;        

    if (command == NULL)
      {
	fprintf(stderr, "** ERROR **: No command given !");
	return EXIT_FAILURE;
      }


    if ((master = get_pty()) < 0) {
      perror("ptypair: could not open master pty");
      exit (EXIT_FAILURE);
    }
    lstat(ttydev, &ttyfd_stat);

    /* first, create one pipe. 
     */
    rc = pipe(user_to_translator);
    if (rc == -1) {
        perror("main: pipe user_to_translator");
        exit (EXIT_FAILURE);
    }

    /* then, create another pipe. 
     */
    rc = pipe(translator_to_user);
    if (rc == -1) {
        perror("main: pipe translator_to_user");
        exit (EXIT_FAILURE);
    }

    /* then, create yet another pipe. 
     */
    rc = pipe(err_to_user);
    if (rc == -1) {
        perror("main: pipe err_to_user");
        exit (EXIT_FAILURE);
    }

    /* now fork off a child process, and set their handling routines. */
    pid = fork();

    switch (pid) {

        case -1:        /* fork failed. */

	  perror("main: fork");
	  memset (password, 0, 128);
	  memset (passphrase, 0, 128);
	  exit (EXIT_FAILURE);

        case 0:         /* child process.  */

	  /* page lock is not inherited after
	   * the fork
	   */
	  memset (password, 0, 128);
	  memset (passphrase, 0, 128);

	  /* We are in the child process */

	  /****************************************
	  close(master);

	  if (setsid() < 0) {
	    perror("could not set session leader");
	  }

	  if ((slave = get_slave_pty(name)) < 0) {
	    perror("ptypair: could not open slave tty");
	    fflush(stdout);
	    _exit (EXIT_FAILURE);
	  }

	  
#ifdef TIOCSCTTY
	  if (ioctl(slave, TIOCSCTTY, NULL)) {
	    perror("could not set new controlling tty");
	  }
#endif

	  dup2(slave, STDIN_FILENO);
	  dup2(slave, 1);
	  dup2(slave, 2);

	  
	  if (slave > 2)
	    close(slave);
	  *************************************/

	  /* establish a controlling teletype for the new session */
	  slave = get_tty();

	  close(master);

	  translator   (command,
			user_to_translator, 
			translator_to_user, 
			err_to_user); 


	  break;

        default:        /* parent process. */


	  child_pid = pid;
	  retval = user_handler (mode, master, 
				 translator_to_user, 
				 user_to_translator, 
				 err_to_user);
	  break;
    }

    /* just to be sure
     */
    (void) waitpid (-1, NULL, WNOHANG|WUNTRACED);
    child_pid = 0;

    close(master);

    restore_tty(ttydev);

    return retval;
}


syntax highlighted by Code2HTML, v. 0.9.1