*** pathnames.h.original	Tue Aug 21 15:45:25 1990
--- pathnames.h	Tue Aug 21 22:24:30 1990
***************
*** 35,37 ****
--- 35,40 ----
  #ifdef BFTPDAEMON
  #define		BFTPPATH	"/usr/ucb/bftp"
  #endif  /* BFTPDAEMON */
+ #ifdef USEPTY
+ #define _PATH_PTY "/usr/local/pty"
+ #endif
*** sys_term.c.original	Tue Aug 21 15:45:31 1990
--- sys_term.c	Tue Aug 21 22:00:56 1990
***************
*** 23,28 ****
--- 23,32 ----
  
  #include "telnetd.h"
  #include "pathnames.h"
+ #ifdef USEPTY
+ #include "sock.h"
+ extern char *ttyname();
+ #endif
  
  #ifdef	NEWINIT
  #include <initreq.h>
***************
*** 354,359 ****
--- 358,364 ----
  
  getpty()
  {
+ #ifndef USEPTY
  	register int p;
  #ifndef CRAY
  	register char c, *p1, *p2;
***************
*** 398,403 ****
--- 403,416 ----
  	}
  #endif	/* CRAY */
  	return(-1);
+ #else USEPTY
+ /* In this new 'n' improved pty-based telnetd, we've already called */
+ /* startslave, which in turn waited to grab pseudo-terminals from the */
+ /* pty program. Global variable pty (grrrr) already has our tty. line */
+ /* has already been filled in by startslave. In fact, there's no point */
+ /* in calling getpty() at all. */
+  return pty;
+ #endif USEPTY
  }
  
  #ifdef	LINEMODE
***************
*** 764,772 ****
--- 777,788 ----
   */
  getptyslave()
  {
+ #ifndef USEPTY
  	register int t = -1;
+ #endif
  
  #ifndef	CRAY
+ #ifndef USEPTY
  	/*
  	 * Disassociate self from control terminal and open ttyp side.
  	 * Set important flags on ttyp and ptyp.
***************
*** 791,796 ****
--- 807,815 ----
  		fatalperror(net, line);
  #endif
  
+ #else USEPTY
+  /* In a pty-based world, this function is rendered similarly useless. */
+ #endif USEPTY
  	init_termbuf();
  #ifndef	USE_TERMIO
  	termbuf.sg.sg_flags |= CRMOD|ANYP|ECHO|XTABS;
***************
*** 812,821 ****
--- 831,846 ----
  #endif
  	set_termbuf();
  #else	/* CRAY */
+ #ifndef USEPTY
  	(void) chown(line, 0, 0);
  	(void) chmod(line, 0600);
+ #endif
  #endif	/* CRAY */
+ #ifndef USEPTY
  	return(t);
+ #else USEPTY
+  /* What's there to return? We've thrown away fdsty. */
+ #endif
  }
  
  #ifdef	NEWINIT
***************
*** 829,842 ****
--- 854,891 ----
   * is necessary to startup the login process on the slave side of the pty.
   */
  
+ #ifdef USEPTY
+ int fdpass[2];
+ int siglerpid;
+ #endif USEPTY
  /* ARGSUSED */
+ #ifndef USEPTY
  startslave(t, host)
  int t;
+ #else USEPTY
+ startslave(host)
+ #endif USEPTY
  char *host;
  {
  	register int i;
  	long time();
  
+ #ifdef USEPTY
+  char strfdpass[10];
+  char ch;
+  int fdmty;
+  int fdsty;
+  char *ttyn;
+  int pgrp;
+  int fd;
+ #endif USEPTY
+ #ifdef USEPTY
+  /* Prepare for receiving pseudo-terminal descriptors from pty. */
+  if (socketpair(AF_UNIX,SOCK_STREAM,0,fdpass) == -1) /* virtually impossible */
+    fatalperror(net,"pty-socketpair");
+  (void) sprintf(strfdpass,"%d",fdpass[1]);
+ 
+ #endif USEPTY
  #ifndef	NEWINIT
  # ifdef	CRAY
  	utmp_sig_init();
***************
*** 845,850 ****
--- 894,902 ----
  	if ((i = fork()) < 0)
  		fatalperror(net, "fork");
  	if (i) {
+ #ifdef USEPTY
+    siglerpid = i;
+ #endif
  # ifdef	CRAY
  		/*
  		 * Cray parent will create utmp entry for child and send
***************
*** 873,881 ****
--- 925,972 ----
  		}
  		utmp_sig_notify(pid);
  # endif	/* CRAY */
+ #ifndef USEPTY
  		(void) close(t);
+ #else USEPTY
+ /* Now we'll receive the descriptors. */
+    (void) close(fdpass[1]);
+    (void) sprintf(line,"/NONexistent");
+    fdmty = fdsty = -1;
+    if (pty_getch(fdpass[0],&ch) == -1)
+      cleanup(); /* XXX: telnetd's finishup handling really sucks. */
+    if (pty_putgetint(fdpass[0],'G',&siglerpid) == -1)
+      cleanup();
+    if (pty_getch(fdpass[0],&ch) == -1)
+      cleanup();
+    if (pty_putgetfd(fdpass[0],'m',&fdmty) == -1)
+      cleanup();
+    if (pty_getch(fdpass[0],&ch) == -1)
+      cleanup();
+    if (pty_putgetfd(fdpass[0],'s',&fdsty) == -1)
+      cleanup();
+    if (!(ttyn = ttyname(fdsty)))
+      cleanup();
+    (void) strncpy(line,ttyn,14);
+    if ((fd = open("/dev/tty",O_RDWR)) != -1)
+     {
+      (void) ioctl(fd,TIOCNOTTY,0); /* detach */
+      (void) close(fd);
+     }
+    (void) close(open(ttyn,O_RDWR)); /* attach ourselves to tty */
+    pty = fdmty;
+    (void) ioctl(fdsty,TIOCGPGRP,&pgrp);
+    (void) setpgrp(0,pgrp);
+    (void) close(fdsty); /* we won't need it for anything else */
+    (void) fcntl(fdpass[0],F_SETFL,FNDELAY); /* XXX */
+ 
+ #endif USEPTY
  	} else {
+ #ifndef USEPTY
  		start_login(t, host);
+ #else USEPTY
+    (void) close(fdpass[0]);
+ 		start_login(host,strfdpass);
+ #endif USEPTY
  		/*NOTREACHED*/
  	}
  #else	/* NEWINIT */
***************
*** 986,994 ****
--- 1077,1095 ----
   * function will turn us into the login process.
   */
  
+ #ifndef USEPTY
  start_login(t, host)
  int t;
+ #else USEPTY
+ /* Added parameter, for dealing with pty: strfdpass, a printable version */
+ /* of the file descriptor for passing more descriptors up to us. */
+ 
+ start_login(host,strfdpass)
+ #endif USEPTY
  char *host;
+ #ifdef USEPTY
+ char *strfdpass;
+ #endif USEPTY
  {
  	register char *cp;
  	register char **argv;
***************
*** 996,1001 ****
--- 1097,1103 ----
  #ifdef	CRAY
  	register char **cpp, **cpp2;
  	utmp_sig_wait();
+ #ifndef USEPTY
  # ifndef TCVHUP
  	setpgrp();
  # endif
***************
*** 1028,1038 ****
--- 1130,1142 ----
  	termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
  	termbuf.c_cflag = EXTB|HUPCL|CS8;
  	set_termbuf();
+ #endif USEPTY
  #endif	/* CRAY */
  
  	/*
  	 * set up standard paths before forking to login
  	 */
+ #ifndef USEPTY
  #ifndef	NO_SETSID
  	if (setsid() < 0)
  		fatalperror(net, "setsid");
***************
*** 1042,1053 ****
--- 1146,1167 ----
  	if (ioctl(t, TIOCSCTTY, (char *)0) < 0)
  		fatalperror(net, "ioctl(sctty)");
  #endif
+ #else USEPTY
+  /* The POSIXish setsid() handling here is pty's responsibility. */
+ #endif USEPTY
  	(void) close(net);
  	(void) close(pty);
+ #ifndef USEPTY
  	(void) dup2(t, 0);
  	(void) dup2(t, 1);
  	(void) dup2(t, 2);
  	(void) close(t);
+ #else USEPTY
+         (void) close(0); /* ahhh, life is easy */
+         (void) close(1);
+         (void) close(2);
+ 	/* but absolutely don't close fdpass. */
+ #endif USEPTY
  	/*
  	 * -h : pass on name of host.
  	 *		WARNING:  -h is accepted by login if and only if
***************
*** 1054,1060 ****
--- 1168,1183 ----
  	 *			getuid() == 0.
  	 * -p : don't clobber the environment (so terminal type stays set).
  	 */
+ #ifdef USEPTY
+  /* Stick the pty magic in front. */
+  argv = addarg(0,   "pty"); /* this addarg stuff is stupid */
+  argv = addarg(argv,"-sdf");
+  argv = addarg(argv,strfdpass);
+  argv = addarg(argv,"-xRCUWX"); /* XXX: -xr? */
+  argv = addarg(argv,_PATH_LOGIN);
+ #else
  	argv = addarg(0, "login");
+ #endif
  	argv = addarg(argv, "-h");
  	argv = addarg(argv, host);
  #if	!defined(CRAY) && !defined(NO_LOGIN_P)
***************
*** 1084,1090 ****
--- 1207,1217 ----
  	}
  #endif
  
+ #ifdef USEPTY
+  execv(_PATH_PTY,argv);
+ #else USEPTY
  	execv(_PATH_LOGIN, argv);
+ #endif USEPTY
  
  	syslog(LOG_ERR, "%s: %m\n", _PATH_LOGIN);
  	fatalperror(net, _PATH_LOGIN);
***************
*** 1142,1155 ****
--- 1269,1294 ----
  	p = line + sizeof("/dev/") - 1;
  	if (logout(p))
  		logwtmp(p, "", "");
+ #ifndef USEPTY
  	(void)chmod(line, 0666);
+ #else USEPTY
+ 	(void) chmod(line,0600); /* banish these security holes! */
+ #endif USEPTY
  	(void)chown(line, 0, 0);
  	*p = 'p';
+ #ifndef USEPTY
  	(void)chmod(line, 0666);
+ #else USEPTY
+ 	(void) chmod(line,0600);
+ #endif USEPTY
  	(void)chown(line, 0, 0);
  # else
  	rmut();
+ #ifndef USEPTY
  	vhangup();	/* XXX */
+ #else USEPTY
+ /*	vhangup();        XXX: This is also pty's responsibility. */
+ #endif USEPTY
  # endif
  	(void) shutdown(net, 2);
  #else	/* CRAY */
***************
*** 1156,1162 ****
--- 1295,1306 ----
  # ifndef NEWINIT
  	rmut(line);
  	(void) shutdown(net, 2);
+ #ifndef USEPTY
  	kill(0, SIGHUP);
+ #else USEPTY
+ /* kill(0, SIGHUP);    The pty master makes this decision. */
+  (void) kill(siglerpid,SIGHUP); /* but we do have to tell the sigler. */
+ #endif USEPTY
  # else	/* NEWINIT */
  	(void) shutdown(net, 2);
  # endif	/* NEWINT */
***************
*** 1273,1282 ****
--- 1417,1434 ----
  			(void) close(f);
  		}
  	}
+ #ifndef USEPTY
  	(void) chmod(line, 0666);
+ #else USEPTY
+ 	(void) chmod(line, 0600);
+ #endif USEPTY
  	(void) chown(line, 0, 0);
  	line[strlen("/dev/")] = 'p';
+ #ifndef USEPTY
  	(void) chmod(line, 0666);
+ #else USEPTY
+ 	(void) chmod(line, 0600);
+ #endif USEPTY
  	(void) chown(line, 0, 0);
  }  /* end of rmut */
  #endif	/* CRAY */
*** telnetd.c.original	Tue Aug 21 15:45:36 1990
--- telnetd.c	Tue Aug 21 21:27:48 1990
***************
*** 28,33 ****
--- 28,37 ----
  #endif /* not lint */
  
  #include "telnetd.h"
+ #ifdef USEPTY
+ #include "sock.h"
+ extern char *ttyname();
+ #endif USEPTY
  
  /*
   * I/O data buffers,
***************
*** 462,467 ****
--- 466,472 ----
  	int t;
  	struct hostent *hp;
  
+ #ifndef USEPTY
  	/*
  	 * Find an available pty to use.
  	 */
***************
*** 470,475 ****
--- 475,481 ----
  		fatal(net, "All network ports in use");
  
  	t = getptyslave();
+ #endif USEPTY
  
  	/* get name of connected client */
  	hp = gethostbyaddr((char *)&who->sin_addr, sizeof (struct in_addr),
***************
*** 489,500 ****
--- 495,533 ----
  	/*
  	 * Start up the login process on the slave side of the terminal
  	 */
+ #ifndef USEPTY
  	startslave(t, host);
+ #else USEPTY
+ 	startslave(host);
+ #endif USEPTY
  
+ #ifdef USEPTY
+ /* In this pty-based version of the world, life is easy. startslave() */
+ /* actually dumps its process under the pty program, which handles all */
+ /* those nasty details of finding a pty and getting it started. pty */
+ /* then passes its pty master side up to telnetd (the ``controller'') */
+ /* so that we have full control. Joy to the world. */
+ 
+ 	/*
+ 	 * Find an available pty to use.
+ 	 */
+ 	pty = getpty(); /* noop */
+ 	if (pty < 0) /* impossible */
+ 		fatal(net, "All network ports in use");
+ 
+ 	getptyslave();
+ 
+ #endif USEPTY
  	telnet(net, pty);  /* begin server processing */
  	/*NOTREACHED*/
  }  /* end of doit */
  
+ #ifdef USEPTY
+ extern int fdpass[2];
+ extern int siglerpid;
+ char ch;
+ 
+ #endif USEPTY
  #ifndef	MAXHOSTNAMELEN
  #define	MAXHOSTNAMELEN 64
  #endif	MAXHOSTNAMELEN
***************
*** 775,780 ****
--- 808,819 ----
  		if (!SYNCHing) {
  			FD_SET(f, &xbits);
  		}
+ #ifdef USEPTY
+      FD_SET(fdpass[0],&ibits);
+      /* When we get input on fdpass, we're switching ttys. */
+      /* This FD_SET seems logical, but it invites bugs under many */
+      /* implementations. XXX. */
+ #endif USEPTY
  		if ((c = select(16, &ibits, &obits, &xbits,
  						(struct timeval *)0)) < 1) {
  			if (c == -1) {
***************
*** 785,791 ****
--- 824,899 ----
  			sleep(5);
  			continue;
  		}
+ #ifdef USEPTY
+ 		if (pty_getch(fdpass[0],&ch) != -1)
+ 		 {
+ 		  /* reconnect... */
+ 		  int fdmty;
+ 		  int fdsty;
+ 		  char *ttyn;
+ 		  int pgrp;
+ 		  int fd;
  
+ 		  fdmty = fdsty = -1;
+ 		  (void) fcntl(fdpass[0],F_SETFL,0); /*XXX*/
+ 		  if (ch != 'G')
+ 		    if (pty_getch(fdpass[0],&ch) == -1)
+ 		      ;
+ 		  if (pty_putgetint(fdpass[0],'G',&siglerpid) == -1)
+ 		    cleanup();
+ 		  if (pty_getch(fdpass[0],&ch) == -1)
+ 		    cleanup();
+ 		  if (pty_putgetfd(fdpass[0],'m',&fdmty) == -1)
+ 		    cleanup();
+ 		  if (pty_getch(fdpass[0],&ch) == -1)
+ 		    cleanup();
+ 		  if (pty_putgetfd(fdpass[0],'s',&fdsty) == -1)
+ 		    cleanup();
+ 		  if (!(ttyn = ttyname(fdsty)))
+ 		    cleanup();
+ 		  /* It's impossible to do anything sensible with utmp; */
+ 		  /* this shows very clearly why utmp's remote field */
+ 		  /* is inconsistent. So we stick to the same ``line.'' */
+ 
+ 		  fd = 0;
+ 	          (void) ioctl(p, TIOCPKT, (char *)&fd);
+ 		  /* Packet mode, like NDELAY, is not a polite thing to */
+ 		  /* give someone else. One of those unstated conventions */
+ 		  /* that people should learn... */
+ 
+ 		  if ((fd = open("/dev/tty",O_RDWR)) != -1)
+ 		   {
+ 		    (void) ioctl(fd,TIOCNOTTY,0); /* detach */
+ 		    (void) close(fd);
+ 		   }
+ 		  (void) close(open(ttyn,O_RDWR)); /* attach */
+ 
+                   (void) close(pty);
+ 		  pty = fdmty;
+ 		  p = pty; /* XXX: Blame DAB for this. Whither modularity? */
+ 
+ 	          (void) ioctl(p, TIOCPKT, (char *)&on);
+ 		  /* If we didn't do this, telnetd would become very */
+ 		  /* confused, because it's expecting packet-mode stuff. */
+ 
+ 		  (void) fcntl(fdpass[0],F_SETFL,FNDELAY); /* XXX */
+ 		  (void) ioctl(fdsty,TIOCGPGRP,&pgrp);
+ 		  (void) setpgrp(0,pgrp);
+ 
+ 		  /* XXX: If this messes up Linemode, TOUGH LUCK! */
+ 	          init_termbuf(); /* XXX */
+ #ifdef LINEMODE
+         	  localstat(); /* XXX */
+ #endif
+ 
+ 		  FD_ZERO(&xbits);
+ 		  FD_ZERO(&ibits); /* XXX */
+ 		  FD_ZERO(&obits);
+ 
+ 		  /* XXX: anything else to do? */
+ 		 }
+ #endif USEPTY
+ 
  		/*
  		 * Any urgent data?
  		 */
***************
*** 881,888 ****
--- 989,1004 ----
  			if (pcc < 0 && errno == EWOULDBLOCK)
  				pcc = 0;
  			else {
+ #ifndef USEPTY
  				if (pcc <= 0)
  					break;
+ #else USEPTY
+ 				if (pcc <= 0)
+ 				 {
+ 				  pcc = 0;
+ 				  goto wtfiseofpty;
+ 				 }
+ #endif USEPTY
  #if	!defined(CRAY2) || !defined(UNICOS5)
  #ifdef	LINEMODE
  				/*
***************
*** 932,937 ****
--- 1048,1056 ----
  					ptyip = ptyibuf;
  #endif	/* defined(CRAY2) && defined(UNICOS5) */
  			}
+ #ifdef USEPTY
+  wtfiseofpty: ;
+ #endif USEPTY
  		}
  
  		while (pcc > 0) {
