xref: /csrg-svn/usr.bin/rlogin/rlogin.c (revision 36511)
121595Sdist /*
235539Sbostic  * Copyright (c) 1983 The Regents of the University of California.
335539Sbostic  * All rights reserved.
435539Sbostic  *
535539Sbostic  * Redistribution and use in source and binary forms are permitted
635539Sbostic  * provided that the above copyright notice and this paragraph are
735539Sbostic  * duplicated in all such forms and that any documentation,
835539Sbostic  * advertising materials, and other materials related to such
935539Sbostic  * distribution and use acknowledge that the software was developed
1035539Sbostic  * by the University of California, Berkeley.  The name of the
1135539Sbostic  * University may not be used to endorse or promote products derived
1235539Sbostic  * from this software without specific prior written permission.
1335539Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1435539Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1535539Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1621595Sdist  */
1721595Sdist 
186444Swnj #ifndef lint
1921595Sdist char copyright[] =
2035539Sbostic "@(#) Copyright (c) 1983 The Regents of the University of California.\n\
2121595Sdist  All rights reserved.\n";
2235539Sbostic #endif /* not lint */
236444Swnj 
2421595Sdist #ifndef lint
25*36511Skfall static char sccsid[] = "@(#)rlogin.c	5.12 (Berkeley) 9/19/88";
2635539Sbostic #endif /* not lint */
2721595Sdist 
2812990Ssam /*
2912990Ssam  * rlogin - remote login
3012990Ssam  */
3126981Skarels #include <sys/param.h>
3225424Skarels #include <sys/errno.h>
3324727Smckusick #include <sys/file.h>
346444Swnj #include <sys/socket.h>
3529729Smckusick #include <sys/time.h>
3629729Smckusick #include <sys/resource.h>
3713620Ssam #include <sys/wait.h>
389365Ssam 
399207Ssam #include <netinet/in.h>
409365Ssam 
419365Ssam #include <stdio.h>
429365Ssam #include <sgtty.h>
436444Swnj #include <errno.h>
446444Swnj #include <pwd.h>
459365Ssam #include <signal.h>
4625424Skarels #include <setjmp.h>
479365Ssam #include <netdb.h>
486444Swnj 
49*36511Skfall #ifdef	KERBEROS
50*36511Skfall #include <kerberos/krb.h>
51*36511Skfall int		encrypt = 0;
52*36511Skfall char		krb_realm[REALM_SZ];
53*36511Skfall CREDENTIALS	cred;
54*36511Skfall Key_schedule	schedule;
55*36511Skfall #endif	/* KERBEROS */
56*36511Skfall 
5724726Smckusick # ifndef TIOCPKT_WINDOW
5824726Smckusick # define TIOCPKT_WINDOW 0x80
5924726Smckusick # endif TIOCPKT_WINDOW
6024726Smckusick 
6129729Smckusick /* concession to sun */
6229729Smckusick # ifndef SIGUSR1
6329729Smckusick # define SIGUSR1 30
6429729Smckusick # endif SIGUSR1
6529729Smckusick 
6629729Smckusick char	*index(), *rindex(), *malloc(), *getenv(), *strcat(), *strcpy();
676444Swnj struct	passwd *getpwuid();
689365Ssam char	*name;
696444Swnj int	rem;
706444Swnj char	cmdchar = '~';
716444Swnj int	eight;
7221583Sbloom int	litout;
736444Swnj char	*speeds[] =
746444Swnj     { "0", "50", "75", "110", "134", "150", "200", "300",
756444Swnj       "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" };
7618358Ssam char	term[256] = "network";
779365Ssam extern	int errno;
789365Ssam int	lostpeer();
7924726Smckusick int	dosigwinch = 0;
8026981Skarels #ifndef sigmask
8126981Skarels #define sigmask(m)	(1 << ((m)-1))
8226981Skarels #endif
8326981Skarels #ifdef sun
8426981Skarels struct winsize {
8526981Skarels 	unsigned short ws_row, ws_col;
8626981Skarels 	unsigned short ws_xpixel, ws_ypixel;
8726981Skarels };
8829729Smckusick #endif sun
8918358Ssam struct	winsize winsize;
9024726Smckusick int	sigwinch(), oob();
916444Swnj 
9229729Smckusick /*
9329729Smckusick  * The following routine provides compatibility (such as it is)
9429729Smckusick  * between 4.2BSD Suns and others.  Suns have only a `ttysize',
9529729Smckusick  * so we convert it to a winsize.
9629729Smckusick  */
9729729Smckusick #ifdef sun
9829729Smckusick int
9929729Smckusick get_window_size(fd, wp)
10029729Smckusick 	int fd;
10129729Smckusick 	struct winsize *wp;
10229729Smckusick {
10329729Smckusick 	struct ttysize ts;
10429729Smckusick 	int error;
10529729Smckusick 
10629729Smckusick 	if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0)
10729729Smckusick 		return (error);
10829729Smckusick 	wp->ws_row = ts.ts_lines;
10929729Smckusick 	wp->ws_col = ts.ts_cols;
11029729Smckusick 	wp->ws_xpixel = 0;
11129729Smckusick 	wp->ws_ypixel = 0;
11229729Smckusick 	return (0);
11329729Smckusick }
11429729Smckusick #else sun
11529729Smckusick #define get_window_size(fd, wp)	ioctl(fd, TIOCGWINSZ, wp)
11629729Smckusick #endif sun
11729729Smckusick 
1186444Swnj main(argc, argv)
1196444Swnj 	int argc;
1206444Swnj 	char **argv;
1216444Swnj {
1229365Ssam 	char *host, *cp;
1236444Swnj 	struct sgttyb ttyb;
1246444Swnj 	struct passwd *pwd;
1259365Ssam 	struct servent *sp;
12624726Smckusick 	int uid, options = 0, oldmask;
12717449Slepreau 	int on = 1;
1286444Swnj 
1296444Swnj 	host = rindex(argv[0], '/');
1306444Swnj 	if (host)
1316444Swnj 		host++;
1326444Swnj 	else
1336444Swnj 		host = argv[0];
1346444Swnj 	argv++, --argc;
1356444Swnj 	if (!strcmp(host, "rlogin"))
1366444Swnj 		host = *argv++, --argc;
1376444Swnj another:
13810839Ssam 	if (argc > 0 && !strcmp(*argv, "-d")) {
1396444Swnj 		argv++, argc--;
14010415Ssam 		options |= SO_DEBUG;
1416444Swnj 		goto another;
1426444Swnj 	}
14310839Ssam 	if (argc > 0 && !strcmp(*argv, "-l")) {
1446444Swnj 		argv++, argc--;
1456444Swnj 		if (argc == 0)
1466444Swnj 			goto usage;
1476444Swnj 		name = *argv++; argc--;
1486444Swnj 		goto another;
1496444Swnj 	}
15010839Ssam 	if (argc > 0 && !strncmp(*argv, "-e", 2)) {
1516444Swnj 		cmdchar = argv[0][2];
1526444Swnj 		argv++, argc--;
1536444Swnj 		goto another;
1546444Swnj 	}
15510839Ssam 	if (argc > 0 && !strcmp(*argv, "-8")) {
1566444Swnj 		eight = 1;
1576444Swnj 		argv++, argc--;
1586444Swnj 		goto another;
1596444Swnj 	}
16021583Sbloom 	if (argc > 0 && !strcmp(*argv, "-L")) {
16121583Sbloom 		litout = 1;
16221583Sbloom 		argv++, argc--;
16321583Sbloom 		goto another;
16421583Sbloom 	}
165*36511Skfall 
166*36511Skfall #ifdef	KERBEROS
167*36511Skfall 	if (argc > 0 && !strcmp(*argv, "-x")) {
168*36511Skfall 		encrypt = 1;
169*36511Skfall 		des_set_key(cred.session, schedule);
170*36511Skfall 		argv++, argc--;
171*36511Skfall 		goto another;
172*36511Skfall 	}
173*36511Skfall #endif	/* KERBEROS */
174*36511Skfall 
1756444Swnj 	if (host == 0)
1766444Swnj 		goto usage;
1776444Swnj 	if (argc > 0)
1786444Swnj 		goto usage;
1796444Swnj 	pwd = getpwuid(getuid());
1806444Swnj 	if (pwd == 0) {
1816444Swnj 		fprintf(stderr, "Who are you?\n");
1826444Swnj 		exit(1);
1836444Swnj 	}
1849365Ssam 	sp = getservbyname("login", "tcp");
1859365Ssam 	if (sp == 0) {
1869365Ssam 		fprintf(stderr, "rlogin: login/tcp: unknown service\n");
1879365Ssam 		exit(2);
1889365Ssam 	}
1899241Ssam 	cp = getenv("TERM");
1909241Ssam 	if (cp)
19129729Smckusick 		(void) strcpy(term, cp);
19218358Ssam 	if (ioctl(0, TIOCGETP, &ttyb) == 0) {
19329729Smckusick 		(void) strcat(term, "/");
19429729Smckusick 		(void) strcat(term, speeds[ttyb.sg_ospeed]);
1956444Swnj 	}
19629729Smckusick 	(void) get_window_size(0, &winsize);
19729729Smckusick 	(void) signal(SIGPIPE, lostpeer);
19829729Smckusick 	/* will use SIGUSR1 for window size hack, so hold it off */
19929729Smckusick 	oldmask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1));
200*36511Skfall 
201*36511Skfall #ifdef	KERBEROS
202*36511Skfall 	rem = KSUCCESS;
203*36511Skfall 	if(krb_realm[0] == '\0') {
204*36511Skfall 		rem = get_krbrlm(krb_realm, 1);
205*36511Skfall 	}
206*36511Skfall 	if(rem == KSUCCESS) {
207*36511Skfall 		if(encrypt) {
208*36511Skfall 			rem = krcmd_mutual(
209*36511Skfall 				&host, sp->s_port,
210*36511Skfall 				name ? name : pwd->pw_name, term,
211*36511Skfall 				0, krb_realm,
212*36511Skfall 				&cred, schedule
213*36511Skfall 			);
214*36511Skfall 		} else {
215*36511Skfall 			rem = krcmd(
216*36511Skfall 			    	&host, sp->s_port,
217*36511Skfall 			    	name ? name : pwd->pw_name, term,
218*36511Skfall 			    	0, krb_realm
219*36511Skfall 			);
220*36511Skfall 		}
221*36511Skfall 	} else {
222*36511Skfall 		fprintf(
223*36511Skfall 			stderr,
224*36511Skfall 			"rlogin: Kerberos error getting local realm %s\n",
225*36511Skfall 			krb_err_txt[rem]
226*36511Skfall 		);
227*36511Skfall 		exit(1);
228*36511Skfall 	}
229*36511Skfall 
230*36511Skfall #else	/* !KERBEROS */
231*36511Skfall 
2329365Ssam         rem = rcmd(&host, sp->s_port, pwd->pw_name,
2336444Swnj 	    name ? name : pwd->pw_name, term, 0);
234*36511Skfall 
235*36511Skfall #endif	/* KERBEROS */
236*36511Skfall 
237*36511Skfall 	if(rem < 0)
238*36511Skfall 		exit(1);
239*36511Skfall 
24010415Ssam 	if (options & SO_DEBUG &&
24117449Slepreau 	    setsockopt(rem, SOL_SOCKET, SO_DEBUG, &on, sizeof (on)) < 0)
24210415Ssam 		perror("rlogin: setsockopt (SO_DEBUG)");
2439365Ssam 	uid = getuid();
2449365Ssam 	if (setuid(uid) < 0) {
2459365Ssam 		perror("rlogin: setuid");
2469365Ssam 		exit(1);
2479365Ssam 	}
24824726Smckusick 	doit(oldmask);
2499365Ssam 	/*NOTREACHED*/
2506444Swnj usage:
2516444Swnj 	fprintf(stderr,
252*36511Skfall #ifdef	KERBEROS
253*36511Skfall 	    "usage: rlogin host [ -ex ] [ -l username ] [ -8 ] [ -L ] [ -x ]\n");
254*36511Skfall #else
25525341Smckusick 	    "usage: rlogin host [ -ex ] [ -l username ] [ -8 ] [ -L ]\n");
256*36511Skfall #endif
2576444Swnj 	exit(1);
2586444Swnj }
2596444Swnj 
2606444Swnj #define CRLF "\r\n"
2616444Swnj 
2629365Ssam int	child;
26311803Sedward int	catchild();
26429729Smckusick int	copytochild(), writeroob();
2659365Ssam 
26613075Ssam int	defflags, tabflag;
26721583Sbloom int	deflflags;
26813075Ssam char	deferase, defkill;
26913075Ssam struct	tchars deftc;
27013075Ssam struct	ltchars defltc;
27113075Ssam struct	tchars notc =	{ -1, -1, -1, -1, -1, -1 };
27213075Ssam struct	ltchars noltc =	{ -1, -1, -1, -1, -1, -1 };
2736444Swnj 
27424726Smckusick doit(oldmask)
2756444Swnj {
2766444Swnj 	int exit();
27713075Ssam 	struct sgttyb sb;
2786444Swnj 
27929729Smckusick 	(void) ioctl(0, TIOCGETP, (char *)&sb);
28013075Ssam 	defflags = sb.sg_flags;
28112155Ssam 	tabflag = defflags & TBDELAY;
2829962Ssam 	defflags &= ECHO | CRMOD;
28313075Ssam 	deferase = sb.sg_erase;
28413075Ssam 	defkill = sb.sg_kill;
28529729Smckusick 	(void) ioctl(0, TIOCLGET, (char *)&deflflags);
28629729Smckusick 	(void) ioctl(0, TIOCGETC, (char *)&deftc);
28713075Ssam 	notc.t_startc = deftc.t_startc;
28813075Ssam 	notc.t_stopc = deftc.t_stopc;
28929729Smckusick 	(void) ioctl(0, TIOCGLTC, (char *)&defltc);
29029729Smckusick 	(void) signal(SIGINT, SIG_IGN);
29129729Smckusick 	setsignal(SIGHUP, exit);
29229729Smckusick 	setsignal(SIGQUIT, exit);
2939365Ssam 	child = fork();
2949365Ssam 	if (child == -1) {
2959365Ssam 		perror("rlogin: fork");
29625424Skarels 		done(1);
2979365Ssam 	}
2989365Ssam 	if (child == 0) {
29924726Smckusick 		mode(1);
30029729Smckusick 		if (reader(oldmask) == 0) {
30125424Skarels 			prf("Connection closed.");
30225424Skarels 			exit(0);
30325424Skarels 		}
30412155Ssam 		sleep(1);
30512155Ssam 		prf("\007Connection closed.");
3066444Swnj 		exit(3);
3076444Swnj 	}
30829729Smckusick 
30929729Smckusick 	/*
31029729Smckusick 	 * We may still own the socket, and may have a pending SIGURG
31129729Smckusick 	 * (or might receive one soon) that we really want to send to
31229729Smckusick 	 * the reader.  Set a trap that simply copies such signals to
31329729Smckusick 	 * the child.
31429729Smckusick 	 */
31529729Smckusick 	(void) signal(SIGURG, copytochild);
31629729Smckusick 	(void) signal(SIGUSR1, writeroob);
31729729Smckusick 	(void) sigsetmask(oldmask);
31829729Smckusick 	(void) signal(SIGCHLD, catchild);
3199365Ssam 	writer();
32012155Ssam 	prf("Closed connection.");
32125424Skarels 	done(0);
3226444Swnj }
3236444Swnj 
32429729Smckusick /*
32529729Smckusick  * Trap a signal, unless it is being ignored.
32629729Smckusick  */
32729729Smckusick setsignal(sig, act)
32829729Smckusick 	int sig, (*act)();
32929729Smckusick {
33029729Smckusick 	int omask = sigblock(sigmask(sig));
33129729Smckusick 
33229729Smckusick 	if (signal(sig, act) == SIG_IGN)
33329729Smckusick 		(void) signal(sig, SIG_IGN);
33429729Smckusick 	(void) sigsetmask(omask);
33529729Smckusick }
33629729Smckusick 
33725424Skarels done(status)
33825424Skarels 	int status;
3396444Swnj {
34029729Smckusick 	int w;
3416444Swnj 
3426444Swnj 	mode(0);
34329729Smckusick 	if (child > 0) {
34429729Smckusick 		/* make sure catchild does not snap it up */
34529729Smckusick 		(void) signal(SIGCHLD, SIG_DFL);
34629729Smckusick 		if (kill(child, SIGKILL) >= 0)
34729729Smckusick 			while ((w = wait((union wait *)0)) > 0 && w != child)
34829729Smckusick 				/*void*/;
34929729Smckusick 	}
35025424Skarels 	exit(status);
3516444Swnj }
3526444Swnj 
35324726Smckusick /*
35429729Smckusick  * Copy SIGURGs to the child process.
35529729Smckusick  */
35629729Smckusick copytochild()
35729729Smckusick {
35829729Smckusick 
35929729Smckusick 	(void) kill(child, SIGURG);
36029729Smckusick }
36129729Smckusick 
36229729Smckusick /*
36324726Smckusick  * This is called when the reader process gets the out-of-band (urgent)
36424726Smckusick  * request to turn on the window-changing protocol.
36524726Smckusick  */
36624726Smckusick writeroob()
36724726Smckusick {
36824726Smckusick 
36925341Smckusick 	if (dosigwinch == 0) {
37024919Smckusick 		sendwindow();
37129729Smckusick 		(void) signal(SIGWINCH, sigwinch);
37225341Smckusick 	}
37324726Smckusick 	dosigwinch = 1;
37424726Smckusick }
37524726Smckusick 
37611803Sedward catchild()
37711803Sedward {
37811803Sedward 	union wait status;
37911803Sedward 	int pid;
38011803Sedward 
38111803Sedward again:
38229729Smckusick 	pid = wait3(&status, WNOHANG|WUNTRACED, (struct rusage *)0);
38311803Sedward 	if (pid == 0)
38411803Sedward 		return;
38511803Sedward 	/*
38611803Sedward 	 * if the child (reader) dies, just quit
38711803Sedward 	 */
38811803Sedward 	if (pid < 0 || pid == child && !WIFSTOPPED(status))
38929729Smckusick 		done((int)(status.w_termsig | status.w_retcode));
39011803Sedward 	goto again;
39111803Sedward }
39211803Sedward 
3936444Swnj /*
3949365Ssam  * writer: write to remote: 0 -> line.
3959365Ssam  * ~.	terminate
3969365Ssam  * ~^Z	suspend rlogin process.
39710415Ssam  * ~^Y  suspend rlogin process, but leave reader alone.
3986444Swnj  */
3999365Ssam writer()
4006444Swnj {
40123530Sbloom 	char c;
40211803Sedward 	register n;
40323530Sbloom 	register bol = 1;               /* beginning of line */
40423530Sbloom 	register local = 0;
4056444Swnj 
40611803Sedward 	for (;;) {
40711803Sedward 		n = read(0, &c, 1);
40818358Ssam 		if (n <= 0) {
40918358Ssam 			if (n < 0 && errno == EINTR)
41018358Ssam 				continue;
41111803Sedward 			break;
41218358Ssam 		}
4139365Ssam 		/*
4149365Ssam 		 * If we're at the beginning of the line
4159365Ssam 		 * and recognize a command character, then
4169365Ssam 		 * we echo locally.  Otherwise, characters
4179365Ssam 		 * are echo'd remotely.  If the command
4189365Ssam 		 * character is doubled, this acts as a
4199365Ssam 		 * force and local echo is suppressed.
4209365Ssam 		 */
42123530Sbloom 		if (bol) {
42223530Sbloom 			bol = 0;
42323530Sbloom 			if (c == cmdchar) {
42423530Sbloom 				bol = 0;
42523530Sbloom 				local = 1;
42623530Sbloom 				continue;
4276444Swnj 			}
42823530Sbloom 		} else if (local) {
42923530Sbloom 			local = 0;
43023530Sbloom 			if (c == '.' || c == deftc.t_eofc) {
43123530Sbloom 				echo(c);
43223530Sbloom 				break;
4336444Swnj 			}
43423530Sbloom 			if (c == defltc.t_suspc || c == defltc.t_dsuspc) {
43523530Sbloom 				bol = 1;
43623530Sbloom 				echo(c);
43723530Sbloom 				stop(c);
43823530Sbloom 				continue;
43923530Sbloom 			}
440*36511Skfall 			if (c != cmdchar) {
441*36511Skfall #ifdef	KERBEROS
442*36511Skfall 				if(encrypt) {
443*36511Skfall 					(void) des_write(
444*36511Skfall 						rem,
445*36511Skfall 						&cmdchar,
446*36511Skfall 						1
447*36511Skfall 					);
448*36511Skfall 				} else
449*36511Skfall #endif
450*36511Skfall 					(void) write(
451*36511Skfall 						rem,
452*36511Skfall 						&cmdchar,
453*36511Skfall 						1
454*36511Skfall 					);
455*36511Skfall 			}
4566444Swnj 		}
457*36511Skfall 
458*36511Skfall #ifdef	KERBEROS
459*36511Skfall 		if(encrypt) {
460*36511Skfall 			if (des_write(rem, &c, 1) == 0) {
461*36511Skfall 				prf("line gone");
462*36511Skfall 				break;
463*36511Skfall 			}
464*36511Skfall 		} else
465*36511Skfall #endif
466*36511Skfall 			if (write(rem, &c, 1) == 0) {
467*36511Skfall 				prf("line gone");
468*36511Skfall 				break;
469*36511Skfall 			}
47023530Sbloom 		bol = c == defkill || c == deftc.t_eofc ||
47125424Skarels 		    c == deftc.t_intrc || c == defltc.t_suspc ||
47223530Sbloom 		    c == '\r' || c == '\n';
4736444Swnj 	}
4746444Swnj }
4756444Swnj 
47623530Sbloom echo(c)
47723530Sbloom register char c;
47823530Sbloom {
47923530Sbloom 	char buf[8];
48023530Sbloom 	register char *p = buf;
48123530Sbloom 
48223530Sbloom 	c &= 0177;
48323530Sbloom 	*p++ = cmdchar;
48423530Sbloom 	if (c < ' ') {
48523530Sbloom 		*p++ = '^';
48623530Sbloom 		*p++ = c + '@';
48723530Sbloom 	} else if (c == 0177) {
48823530Sbloom 		*p++ = '^';
48923530Sbloom 		*p++ = '?';
49023530Sbloom 	} else
49123530Sbloom 		*p++ = c;
49223530Sbloom 	*p++ = '\r';
49323530Sbloom 	*p++ = '\n';
49429729Smckusick 	(void) write(1, buf, p - buf);
49523530Sbloom }
49623530Sbloom 
49718358Ssam stop(cmdc)
49818358Ssam 	char cmdc;
49918358Ssam {
50018358Ssam 	mode(0);
50129729Smckusick 	(void) signal(SIGCHLD, SIG_IGN);
50229729Smckusick 	(void) kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP);
50329729Smckusick 	(void) signal(SIGCHLD, catchild);
50418358Ssam 	mode(1);
50518358Ssam 	sigwinch();			/* check for size changes */
50618358Ssam }
50718358Ssam 
50818358Ssam sigwinch()
50918358Ssam {
51018358Ssam 	struct winsize ws;
51118358Ssam 
51229729Smckusick 	if (dosigwinch && get_window_size(0, &ws) == 0 &&
51318358Ssam 	    bcmp(&ws, &winsize, sizeof (ws))) {
51418358Ssam 		winsize = ws;
51524726Smckusick 		sendwindow();
51618358Ssam 	}
51718358Ssam }
51818358Ssam 
51924726Smckusick /*
52024726Smckusick  * Send the window size to the server via the magic escape
52124726Smckusick  */
52224726Smckusick sendwindow()
52324726Smckusick {
52424726Smckusick 	char obuf[4 + sizeof (struct winsize)];
52524726Smckusick 	struct winsize *wp = (struct winsize *)(obuf+4);
52624726Smckusick 
52724726Smckusick 	obuf[0] = 0377;
52824726Smckusick 	obuf[1] = 0377;
52924726Smckusick 	obuf[2] = 's';
53024726Smckusick 	obuf[3] = 's';
53124726Smckusick 	wp->ws_row = htons(winsize.ws_row);
53224726Smckusick 	wp->ws_col = htons(winsize.ws_col);
53324726Smckusick 	wp->ws_xpixel = htons(winsize.ws_xpixel);
53424726Smckusick 	wp->ws_ypixel = htons(winsize.ws_ypixel);
535*36511Skfall 
536*36511Skfall #ifdef	KERBEROS
537*36511Skfall 	if(encrypt)
538*36511Skfall 		(void) des_write(rem, obuf, sizeof(obuf));
539*36511Skfall 	else
540*36511Skfall #endif
541*36511Skfall 		(void) write(rem, obuf, sizeof(obuf));
54224726Smckusick }
54324726Smckusick 
54425424Skarels /*
54525424Skarels  * reader: read from remote: line -> 1
54625424Skarels  */
54725424Skarels #define	READING	1
54825424Skarels #define	WRITING	2
54925424Skarels 
55025424Skarels char	rcvbuf[8 * 1024];
55125424Skarels int	rcvcnt;
55225424Skarels int	rcvstate;
55326981Skarels int	ppid;
55425424Skarels jmp_buf	rcvtop;
55525424Skarels 
5566444Swnj oob()
5576444Swnj {
55825424Skarels 	int out = FWRITE, atmark, n;
55925424Skarels 	int rcvd = 0;
5609365Ssam 	char waste[BUFSIZ], mark;
56124726Smckusick 	struct sgttyb sb;
5626444Swnj 
56325424Skarels 	while (recv(rem, &mark, 1, MSG_OOB) < 0)
56425424Skarels 		switch (errno) {
56525424Skarels 
56625424Skarels 		case EWOULDBLOCK:
56725424Skarels 			/*
56825424Skarels 			 * Urgent data not here yet.
56925424Skarels 			 * It may not be possible to send it yet
57025424Skarels 			 * if we are blocked for output
57125424Skarels 			 * and our input buffer is full.
57225424Skarels 			 */
57325424Skarels 			if (rcvcnt < sizeof(rcvbuf)) {
57425424Skarels 				n = read(rem, rcvbuf + rcvcnt,
57525424Skarels 					sizeof(rcvbuf) - rcvcnt);
57625424Skarels 				if (n <= 0)
57725424Skarels 					return;
57825424Skarels 				rcvd += n;
57925424Skarels 			} else {
58025424Skarels 				n = read(rem, waste, sizeof(waste));
58125424Skarels 				if (n <= 0)
58225424Skarels 					return;
58325424Skarels 			}
58425424Skarels 			continue;
58525424Skarels 
58625424Skarels 		default:
58725424Skarels 			return;
5886444Swnj 	}
58925424Skarels 	if (mark & TIOCPKT_WINDOW) {
59024726Smckusick 		/*
59124726Smckusick 		 * Let server know about window size changes
59224726Smckusick 		 */
59329729Smckusick 		(void) kill(ppid, SIGUSR1);
59424726Smckusick 	}
59525424Skarels 	if (!eight && (mark & TIOCPKT_NOSTOP)) {
59629729Smckusick 		(void) ioctl(0, TIOCGETP, (char *)&sb);
59724726Smckusick 		sb.sg_flags &= ~CBREAK;
59824726Smckusick 		sb.sg_flags |= RAW;
59929729Smckusick 		(void) ioctl(0, TIOCSETN, (char *)&sb);
60013075Ssam 		notc.t_stopc = -1;
60113075Ssam 		notc.t_startc = -1;
60229729Smckusick 		(void) ioctl(0, TIOCSETC, (char *)&notc);
6036444Swnj 	}
60425424Skarels 	if (!eight && (mark & TIOCPKT_DOSTOP)) {
60529729Smckusick 		(void) ioctl(0, TIOCGETP, (char *)&sb);
60624726Smckusick 		sb.sg_flags &= ~RAW;
60724726Smckusick 		sb.sg_flags |= CBREAK;
60829729Smckusick 		(void) ioctl(0, TIOCSETN, (char *)&sb);
60913075Ssam 		notc.t_stopc = deftc.t_stopc;
61013075Ssam 		notc.t_startc = deftc.t_startc;
61129729Smckusick 		(void) ioctl(0, TIOCSETC, (char *)&notc);
6126444Swnj 	}
61325424Skarels 	if (mark & TIOCPKT_FLUSHWRITE) {
61429729Smckusick 		(void) ioctl(1, TIOCFLUSH, (char *)&out);
61525424Skarels 		for (;;) {
61625424Skarels 			if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
61725424Skarels 				perror("ioctl");
61825424Skarels 				break;
61925424Skarels 			}
62025424Skarels 			if (atmark)
62125424Skarels 				break;
62225424Skarels 			n = read(rem, waste, sizeof (waste));
62325424Skarels 			if (n <= 0)
62425424Skarels 				break;
62525424Skarels 		}
62625424Skarels 		/*
62725424Skarels 		 * Don't want any pending data to be output,
62825424Skarels 		 * so clear the recv buffer.
62925424Skarels 		 * If we were hanging on a write when interrupted,
63025424Skarels 		 * don't want it to restart.  If we were reading,
63125424Skarels 		 * restart anyway.
63225424Skarels 		 */
63325424Skarels 		rcvcnt = 0;
63425424Skarels 		longjmp(rcvtop, 1);
63525424Skarels 	}
63629729Smckusick 
63725424Skarels 	/*
63829729Smckusick 	 * oob does not do FLUSHREAD (alas!)
63929729Smckusick 	 */
64029729Smckusick 
64129729Smckusick 	/*
64225424Skarels 	 * If we filled the receive buffer while a read was pending,
64325424Skarels 	 * longjmp to the top to restart appropriately.  Don't abort
64425424Skarels 	 * a pending write, however, or we won't know how much was written.
64525424Skarels 	 */
64625424Skarels 	if (rcvd && rcvstate == READING)
64725424Skarels 		longjmp(rcvtop, 1);
6486444Swnj }
6496444Swnj 
6509365Ssam /*
6519365Ssam  * reader: read from remote: line -> 1
6529365Ssam  */
65329729Smckusick reader(oldmask)
65429729Smckusick 	int oldmask;
6556444Swnj {
65626981Skarels #if !defined(BSD) || BSD < 43
65726981Skarels 	int pid = -getpid();
65826981Skarels #else
65925424Skarels 	int pid = getpid();
66026981Skarels #endif
66125424Skarels 	int n, remaining;
66225424Skarels 	char *bufp = rcvbuf;
6636444Swnj 
66429729Smckusick 	(void) signal(SIGTTOU, SIG_IGN);
66529729Smckusick 	(void) signal(SIGURG, oob);
66626981Skarels 	ppid = getppid();
66729729Smckusick 	(void) fcntl(rem, F_SETOWN, pid);
66825424Skarels 	(void) setjmp(rcvtop);
66929729Smckusick 	(void) sigsetmask(oldmask);
6706444Swnj 	for (;;) {
67125424Skarels 		while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) {
67225424Skarels 			rcvstate = WRITING;
67325424Skarels 			n = write(1, bufp, remaining);
67425424Skarels 			if (n < 0) {
67525424Skarels 				if (errno != EINTR)
67626189Slepreau 					return (-1);
67725424Skarels 				continue;
67825424Skarels 			}
67925424Skarels 			bufp += n;
68025424Skarels 		}
68125424Skarels 		bufp = rcvbuf;
68225424Skarels 		rcvcnt = 0;
68325424Skarels 		rcvstate = READING;
684*36511Skfall 
685*36511Skfall #ifdef	KERBEROS
686*36511Skfall 		if(encrypt)
687*36511Skfall 			rcvcnt = des_read(rem, rcvbuf, sizeof(rcvbuf));
688*36511Skfall 		else
689*36511Skfall #endif
690*36511Skfall 			rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf));
69125424Skarels 		if (rcvcnt == 0)
69225424Skarels 			return (0);
69325424Skarels 		if (rcvcnt < 0) {
6949365Ssam 			if (errno == EINTR)
6956444Swnj 				continue;
69626981Skarels 			perror("read");
69725424Skarels 			return (-1);
6986444Swnj 		}
6996444Swnj 	}
7006444Swnj }
7016444Swnj 
7026444Swnj mode(f)
7036444Swnj {
70413075Ssam 	struct tchars *tc;
70513075Ssam 	struct ltchars *ltc;
70613075Ssam 	struct sgttyb sb;
70721583Sbloom 	int	lflags;
7089365Ssam 
70929729Smckusick 	(void) ioctl(0, TIOCGETP, (char *)&sb);
71029729Smckusick 	(void) ioctl(0, TIOCLGET, (char *)&lflags);
7119962Ssam 	switch (f) {
7129962Ssam 
7139962Ssam 	case 0:
71413075Ssam 		sb.sg_flags &= ~(CBREAK|RAW|TBDELAY);
71513075Ssam 		sb.sg_flags |= defflags|tabflag;
7169962Ssam 		tc = &deftc;
71713075Ssam 		ltc = &defltc;
71813075Ssam 		sb.sg_kill = defkill;
71913075Ssam 		sb.sg_erase = deferase;
72021583Sbloom 		lflags = deflflags;
7219962Ssam 		break;
7229962Ssam 
7239962Ssam 	case 1:
72413075Ssam 		sb.sg_flags |= (eight ? RAW : CBREAK);
72513075Ssam 		sb.sg_flags &= ~defflags;
72612155Ssam 		/* preserve tab delays, but turn off XTABS */
72713075Ssam 		if ((sb.sg_flags & TBDELAY) == XTABS)
72813075Ssam 			sb.sg_flags &= ~TBDELAY;
7299962Ssam 		tc = &notc;
73013075Ssam 		ltc = &noltc;
73113075Ssam 		sb.sg_kill = sb.sg_erase = -1;
73221583Sbloom 		if (litout)
73321583Sbloom 			lflags |= LLITOUT;
7349962Ssam 		break;
7359962Ssam 
7369962Ssam 	default:
7379962Ssam 		return;
7386444Swnj 	}
73929729Smckusick 	(void) ioctl(0, TIOCSLTC, (char *)ltc);
74029729Smckusick 	(void) ioctl(0, TIOCSETC, (char *)tc);
74129729Smckusick 	(void) ioctl(0, TIOCSETN, (char *)&sb);
74229729Smckusick 	(void) ioctl(0, TIOCLSET, (char *)&lflags);
7436444Swnj }
7446444Swnj 
7459365Ssam /*VARARGS*/
74624726Smckusick prf(f, a1, a2, a3, a4, a5)
7479365Ssam 	char *f;
7486444Swnj {
74929729Smckusick 
75024726Smckusick 	fprintf(stderr, f, a1, a2, a3, a4, a5);
7516444Swnj 	fprintf(stderr, CRLF);
7526444Swnj }
7536444Swnj 
7549365Ssam lostpeer()
7556444Swnj {
75629729Smckusick 
75729729Smckusick 	(void) signal(SIGPIPE, SIG_IGN);
75812155Ssam 	prf("\007Connection closed.");
75925424Skarels 	done(1);
7606444Swnj }
761