xref: /csrg-svn/usr.bin/rlogin/rlogin.c (revision 36628)
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
2536511Skfall 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 
4936511Skfall #ifdef	KERBEROS
5036511Skfall #include <kerberos/krb.h>
5136511Skfall int		encrypt = 0;
5236511Skfall char		krb_realm[REALM_SZ];
5336511Skfall CREDENTIALS	cred;
5436511Skfall Key_schedule	schedule;
5536512Skfall int		use_kerberos = 1;
5636511Skfall #endif	/* KERBEROS */
5736511Skfall 
5824726Smckusick # ifndef TIOCPKT_WINDOW
5924726Smckusick # define TIOCPKT_WINDOW 0x80
6024726Smckusick # endif TIOCPKT_WINDOW
6124726Smckusick 
6229729Smckusick /* concession to sun */
6329729Smckusick # ifndef SIGUSR1
6429729Smckusick # define SIGUSR1 30
6529729Smckusick # endif SIGUSR1
6629729Smckusick 
6729729Smckusick char	*index(), *rindex(), *malloc(), *getenv(), *strcat(), *strcpy();
686444Swnj struct	passwd *getpwuid();
699365Ssam char	*name;
706444Swnj int	rem;
716444Swnj char	cmdchar = '~';
726444Swnj int	eight;
7321583Sbloom int	litout;
746444Swnj char	*speeds[] =
756444Swnj     { "0", "50", "75", "110", "134", "150", "200", "300",
766444Swnj       "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" };
7718358Ssam char	term[256] = "network";
789365Ssam extern	int errno;
799365Ssam int	lostpeer();
8024726Smckusick int	dosigwinch = 0;
8126981Skarels #ifndef sigmask
8226981Skarels #define sigmask(m)	(1 << ((m)-1))
8326981Skarels #endif
8426981Skarels #ifdef sun
8526981Skarels struct winsize {
8626981Skarels 	unsigned short ws_row, ws_col;
8726981Skarels 	unsigned short ws_xpixel, ws_ypixel;
8826981Skarels };
8929729Smckusick #endif sun
9018358Ssam struct	winsize winsize;
9124726Smckusick int	sigwinch(), oob();
926444Swnj 
9329729Smckusick /*
9429729Smckusick  * The following routine provides compatibility (such as it is)
9529729Smckusick  * between 4.2BSD Suns and others.  Suns have only a `ttysize',
9629729Smckusick  * so we convert it to a winsize.
9729729Smckusick  */
9829729Smckusick #ifdef sun
9929729Smckusick int
10029729Smckusick get_window_size(fd, wp)
10129729Smckusick 	int fd;
10229729Smckusick 	struct winsize *wp;
10329729Smckusick {
10429729Smckusick 	struct ttysize ts;
10529729Smckusick 	int error;
10629729Smckusick 
10729729Smckusick 	if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0)
10829729Smckusick 		return (error);
10929729Smckusick 	wp->ws_row = ts.ts_lines;
11029729Smckusick 	wp->ws_col = ts.ts_cols;
11129729Smckusick 	wp->ws_xpixel = 0;
11229729Smckusick 	wp->ws_ypixel = 0;
11329729Smckusick 	return (0);
11429729Smckusick }
11529729Smckusick #else sun
11629729Smckusick #define get_window_size(fd, wp)	ioctl(fd, TIOCGWINSZ, wp)
11729729Smckusick #endif sun
11829729Smckusick 
1196444Swnj main(argc, argv)
1206444Swnj 	int argc;
1216444Swnj 	char **argv;
1226444Swnj {
1239365Ssam 	char *host, *cp;
1246444Swnj 	struct sgttyb ttyb;
1256444Swnj 	struct passwd *pwd;
1269365Ssam 	struct servent *sp;
12724726Smckusick 	int uid, options = 0, oldmask;
12817449Slepreau 	int on = 1;
1296444Swnj 
1306444Swnj 	host = rindex(argv[0], '/');
1316444Swnj 	if (host)
1326444Swnj 		host++;
1336444Swnj 	else
1346444Swnj 		host = argv[0];
1356444Swnj 	argv++, --argc;
1366444Swnj 	if (!strcmp(host, "rlogin"))
1376444Swnj 		host = *argv++, --argc;
1386444Swnj another:
13910839Ssam 	if (argc > 0 && !strcmp(*argv, "-d")) {
1406444Swnj 		argv++, argc--;
14110415Ssam 		options |= SO_DEBUG;
1426444Swnj 		goto another;
1436444Swnj 	}
14410839Ssam 	if (argc > 0 && !strcmp(*argv, "-l")) {
1456444Swnj 		argv++, argc--;
1466444Swnj 		if (argc == 0)
1476444Swnj 			goto usage;
1486444Swnj 		name = *argv++; argc--;
1496444Swnj 		goto another;
1506444Swnj 	}
15110839Ssam 	if (argc > 0 && !strncmp(*argv, "-e", 2)) {
1526444Swnj 		cmdchar = argv[0][2];
1536444Swnj 		argv++, argc--;
1546444Swnj 		goto another;
1556444Swnj 	}
15610839Ssam 	if (argc > 0 && !strcmp(*argv, "-8")) {
1576444Swnj 		eight = 1;
1586444Swnj 		argv++, argc--;
1596444Swnj 		goto another;
1606444Swnj 	}
16121583Sbloom 	if (argc > 0 && !strcmp(*argv, "-L")) {
16221583Sbloom 		litout = 1;
16321583Sbloom 		argv++, argc--;
16421583Sbloom 		goto another;
16521583Sbloom 	}
16636511Skfall 
16736511Skfall #ifdef	KERBEROS
16836511Skfall 	if (argc > 0 && !strcmp(*argv, "-x")) {
16936511Skfall 		encrypt = 1;
17036511Skfall 		des_set_key(cred.session, schedule);
17136511Skfall 		argv++, argc--;
17236511Skfall 		goto another;
17336511Skfall 	}
17436524Skfall 	if (argc > 0 && !strcmp(*argv, "-k")) {
17536524Skfall 		argv++, argc--;
17636524Skfall 		if(argc <= 0 || (**argv == '-')) {
17736524Skfall 			fprintf(stderr, "-k option requires an argument\n");
17836524Skfall 			exit(1);
17936524Skfall 		}
18036524Skfall 		strncpy(krb_realm, *argv, REALM_SZ);
18136524Skfall 		argv++, argc--;
18236524Skfall 		goto another;
18336524Skfall 	}
18436524Skfall 
18536511Skfall #endif	/* KERBEROS */
18636511Skfall 
1876444Swnj 	if (host == 0)
1886444Swnj 		goto usage;
1896444Swnj 	if (argc > 0)
1906444Swnj 		goto usage;
1916444Swnj 	pwd = getpwuid(getuid());
1926444Swnj 	if (pwd == 0) {
1936444Swnj 		fprintf(stderr, "Who are you?\n");
1946444Swnj 		exit(1);
1956444Swnj 	}
19636512Skfall #ifdef	KERBEROS
19736512Skfall 	sp = getservbyname("klogin", "tcp");
19836512Skfall 	if(sp == NULL) {
19936512Skfall 		use_kerberos = 0;
20036512Skfall 		old_warning("klogin service unknown");
20136512Skfall 		sp = getservbyname("login", "tcp");
20236512Skfall 	}
20336512Skfall #else
2049365Ssam 	sp = getservbyname("login", "tcp");
20536512Skfall #endif
2069365Ssam 	if (sp == 0) {
2079365Ssam 		fprintf(stderr, "rlogin: login/tcp: unknown service\n");
2089365Ssam 		exit(2);
2099365Ssam 	}
2109241Ssam 	cp = getenv("TERM");
2119241Ssam 	if (cp)
21229729Smckusick 		(void) strcpy(term, cp);
21318358Ssam 	if (ioctl(0, TIOCGETP, &ttyb) == 0) {
21429729Smckusick 		(void) strcat(term, "/");
21529729Smckusick 		(void) strcat(term, speeds[ttyb.sg_ospeed]);
2166444Swnj 	}
21729729Smckusick 	(void) get_window_size(0, &winsize);
21829729Smckusick 	(void) signal(SIGPIPE, lostpeer);
21929729Smckusick 	/* will use SIGUSR1 for window size hack, so hold it off */
22029729Smckusick 	oldmask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1));
22136511Skfall 
22236511Skfall #ifdef	KERBEROS
22336512Skfall try_connect:
22436512Skfall 	if(use_kerberos) {
22536512Skfall 		rem = KSUCCESS;
22636512Skfall 		if(krb_realm[0] == '\0') {
227*36628Skfall 			rem = krb_get_lrealm(krb_realm, 1);
22836512Skfall 		}
22936512Skfall 		if(rem == KSUCCESS) {
23036512Skfall 			if(encrypt) {
23136512Skfall 				rem = krcmd_mutual(
23236512Skfall 					&host, sp->s_port,
23336512Skfall 					name ? name : pwd->pw_name, term,
23436512Skfall 					0, krb_realm,
23536512Skfall 					&cred, schedule
23636512Skfall 				);
23736512Skfall 			} else {
23836512Skfall 				rem = krcmd(
23936512Skfall 			    		&host, sp->s_port,
24036512Skfall 					name ? name : pwd->pw_name, term,
24136512Skfall 					0, krb_realm
24236512Skfall 				);
24336512Skfall 			}
24436511Skfall 		} else {
24536512Skfall 			fprintf(
24636512Skfall 				stderr,
24736512Skfall 				"rlogin: Kerberos error getting local realm %s\n",
24836512Skfall 				krb_err_txt[rem]
24936511Skfall 			);
25036512Skfall 			exit(1);
25136511Skfall 		}
25236512Skfall 		if((rem < 0) && errno == ECONNREFUSED) {
25336512Skfall 			use_kerberos = 0;
254*36628Skfall 			sp = getservbyname("login", "tcp");
255*36628Skfall 			if(sp == NULL) {
256*36628Skfall 				fprintf(stderr, "unknown service login/tcp\n");
257*36628Skfall 				exit(1);
258*36628Skfall 			}
25936512Skfall 			old_warning("remote host doesn't support Kerberos");
26036512Skfall 			goto try_connect;
26136512Skfall 		}
26236511Skfall 	} else {
26336512Skfall 		if(encrypt) {
26436512Skfall 			fprintf(stderr, "The -x flag requires Kerberos authencation\n");
26536512Skfall 			exit(1);
26636512Skfall 		}
26736512Skfall         	rem = rcmd(&host, sp->s_port, pwd->pw_name,
26836512Skfall 	    		name ? name : pwd->pw_name, term, 0);
26936511Skfall 	}
27036512Skfall #else
27136512Skfall        	rem = rcmd(&host, sp->s_port, pwd->pw_name,
27236512Skfall     		name ? name : pwd->pw_name, term, 0);
27336512Skfall #endif
27436511Skfall 
27536511Skfall 	if(rem < 0)
27636511Skfall 		exit(1);
27736511Skfall 
27810415Ssam 	if (options & SO_DEBUG &&
27917449Slepreau 	    setsockopt(rem, SOL_SOCKET, SO_DEBUG, &on, sizeof (on)) < 0)
28010415Ssam 		perror("rlogin: setsockopt (SO_DEBUG)");
2819365Ssam 	uid = getuid();
2829365Ssam 	if (setuid(uid) < 0) {
2839365Ssam 		perror("rlogin: setuid");
2849365Ssam 		exit(1);
2859365Ssam 	}
28624726Smckusick 	doit(oldmask);
2879365Ssam 	/*NOTREACHED*/
2886444Swnj usage:
2896444Swnj 	fprintf(stderr,
29036511Skfall #ifdef	KERBEROS
29136592Skfall 	    "usage: rlogin host [ -ex ] [ -l username ] [ -k realm ] [ -8 ] [ -L ] [ -x ]\n");
29236511Skfall #else
29325341Smckusick 	    "usage: rlogin host [ -ex ] [ -l username ] [ -8 ] [ -L ]\n");
29436511Skfall #endif
2956444Swnj 	exit(1);
2966444Swnj }
2976444Swnj 
2986444Swnj #define CRLF "\r\n"
2996444Swnj 
3009365Ssam int	child;
30111803Sedward int	catchild();
30229729Smckusick int	copytochild(), writeroob();
3039365Ssam 
30413075Ssam int	defflags, tabflag;
30521583Sbloom int	deflflags;
30613075Ssam char	deferase, defkill;
30713075Ssam struct	tchars deftc;
30813075Ssam struct	ltchars defltc;
30913075Ssam struct	tchars notc =	{ -1, -1, -1, -1, -1, -1 };
31013075Ssam struct	ltchars noltc =	{ -1, -1, -1, -1, -1, -1 };
3116444Swnj 
31224726Smckusick doit(oldmask)
3136444Swnj {
3146444Swnj 	int exit();
31513075Ssam 	struct sgttyb sb;
3166444Swnj 
31729729Smckusick 	(void) ioctl(0, TIOCGETP, (char *)&sb);
31813075Ssam 	defflags = sb.sg_flags;
31912155Ssam 	tabflag = defflags & TBDELAY;
3209962Ssam 	defflags &= ECHO | CRMOD;
32113075Ssam 	deferase = sb.sg_erase;
32213075Ssam 	defkill = sb.sg_kill;
32329729Smckusick 	(void) ioctl(0, TIOCLGET, (char *)&deflflags);
32429729Smckusick 	(void) ioctl(0, TIOCGETC, (char *)&deftc);
32513075Ssam 	notc.t_startc = deftc.t_startc;
32613075Ssam 	notc.t_stopc = deftc.t_stopc;
32729729Smckusick 	(void) ioctl(0, TIOCGLTC, (char *)&defltc);
32829729Smckusick 	(void) signal(SIGINT, SIG_IGN);
32929729Smckusick 	setsignal(SIGHUP, exit);
33029729Smckusick 	setsignal(SIGQUIT, exit);
3319365Ssam 	child = fork();
3329365Ssam 	if (child == -1) {
3339365Ssam 		perror("rlogin: fork");
33425424Skarels 		done(1);
3359365Ssam 	}
3369365Ssam 	if (child == 0) {
33724726Smckusick 		mode(1);
33829729Smckusick 		if (reader(oldmask) == 0) {
33925424Skarels 			prf("Connection closed.");
34025424Skarels 			exit(0);
34125424Skarels 		}
34212155Ssam 		sleep(1);
34312155Ssam 		prf("\007Connection closed.");
3446444Swnj 		exit(3);
3456444Swnj 	}
34629729Smckusick 
34729729Smckusick 	/*
34829729Smckusick 	 * We may still own the socket, and may have a pending SIGURG
34929729Smckusick 	 * (or might receive one soon) that we really want to send to
35029729Smckusick 	 * the reader.  Set a trap that simply copies such signals to
35129729Smckusick 	 * the child.
35229729Smckusick 	 */
35329729Smckusick 	(void) signal(SIGURG, copytochild);
35429729Smckusick 	(void) signal(SIGUSR1, writeroob);
35529729Smckusick 	(void) sigsetmask(oldmask);
35629729Smckusick 	(void) signal(SIGCHLD, catchild);
3579365Ssam 	writer();
35812155Ssam 	prf("Closed connection.");
35925424Skarels 	done(0);
3606444Swnj }
3616444Swnj 
36229729Smckusick /*
36329729Smckusick  * Trap a signal, unless it is being ignored.
36429729Smckusick  */
36529729Smckusick setsignal(sig, act)
36629729Smckusick 	int sig, (*act)();
36729729Smckusick {
36829729Smckusick 	int omask = sigblock(sigmask(sig));
36929729Smckusick 
37029729Smckusick 	if (signal(sig, act) == SIG_IGN)
37129729Smckusick 		(void) signal(sig, SIG_IGN);
37229729Smckusick 	(void) sigsetmask(omask);
37329729Smckusick }
37429729Smckusick 
37525424Skarels done(status)
37625424Skarels 	int status;
3776444Swnj {
37829729Smckusick 	int w;
3796444Swnj 
3806444Swnj 	mode(0);
38129729Smckusick 	if (child > 0) {
38229729Smckusick 		/* make sure catchild does not snap it up */
38329729Smckusick 		(void) signal(SIGCHLD, SIG_DFL);
38429729Smckusick 		if (kill(child, SIGKILL) >= 0)
38529729Smckusick 			while ((w = wait((union wait *)0)) > 0 && w != child)
38629729Smckusick 				/*void*/;
38729729Smckusick 	}
38825424Skarels 	exit(status);
3896444Swnj }
3906444Swnj 
39124726Smckusick /*
39229729Smckusick  * Copy SIGURGs to the child process.
39329729Smckusick  */
39429729Smckusick copytochild()
39529729Smckusick {
39629729Smckusick 
39729729Smckusick 	(void) kill(child, SIGURG);
39829729Smckusick }
39929729Smckusick 
40029729Smckusick /*
40124726Smckusick  * This is called when the reader process gets the out-of-band (urgent)
40224726Smckusick  * request to turn on the window-changing protocol.
40324726Smckusick  */
40424726Smckusick writeroob()
40524726Smckusick {
40624726Smckusick 
40725341Smckusick 	if (dosigwinch == 0) {
40824919Smckusick 		sendwindow();
40929729Smckusick 		(void) signal(SIGWINCH, sigwinch);
41025341Smckusick 	}
41124726Smckusick 	dosigwinch = 1;
41224726Smckusick }
41324726Smckusick 
41411803Sedward catchild()
41511803Sedward {
41611803Sedward 	union wait status;
41711803Sedward 	int pid;
41811803Sedward 
41911803Sedward again:
42029729Smckusick 	pid = wait3(&status, WNOHANG|WUNTRACED, (struct rusage *)0);
42111803Sedward 	if (pid == 0)
42211803Sedward 		return;
42311803Sedward 	/*
42411803Sedward 	 * if the child (reader) dies, just quit
42511803Sedward 	 */
42611803Sedward 	if (pid < 0 || pid == child && !WIFSTOPPED(status))
42729729Smckusick 		done((int)(status.w_termsig | status.w_retcode));
42811803Sedward 	goto again;
42911803Sedward }
43011803Sedward 
4316444Swnj /*
4329365Ssam  * writer: write to remote: 0 -> line.
4339365Ssam  * ~.	terminate
4349365Ssam  * ~^Z	suspend rlogin process.
43510415Ssam  * ~^Y  suspend rlogin process, but leave reader alone.
4366444Swnj  */
4379365Ssam writer()
4386444Swnj {
43923530Sbloom 	char c;
44011803Sedward 	register n;
44123530Sbloom 	register bol = 1;               /* beginning of line */
44223530Sbloom 	register local = 0;
4436444Swnj 
44411803Sedward 	for (;;) {
44511803Sedward 		n = read(0, &c, 1);
44618358Ssam 		if (n <= 0) {
44718358Ssam 			if (n < 0 && errno == EINTR)
44818358Ssam 				continue;
44911803Sedward 			break;
45018358Ssam 		}
4519365Ssam 		/*
4529365Ssam 		 * If we're at the beginning of the line
4539365Ssam 		 * and recognize a command character, then
4549365Ssam 		 * we echo locally.  Otherwise, characters
4559365Ssam 		 * are echo'd remotely.  If the command
4569365Ssam 		 * character is doubled, this acts as a
4579365Ssam 		 * force and local echo is suppressed.
4589365Ssam 		 */
45923530Sbloom 		if (bol) {
46023530Sbloom 			bol = 0;
46123530Sbloom 			if (c == cmdchar) {
46223530Sbloom 				bol = 0;
46323530Sbloom 				local = 1;
46423530Sbloom 				continue;
4656444Swnj 			}
46623530Sbloom 		} else if (local) {
46723530Sbloom 			local = 0;
46823530Sbloom 			if (c == '.' || c == deftc.t_eofc) {
46923530Sbloom 				echo(c);
47023530Sbloom 				break;
4716444Swnj 			}
47223530Sbloom 			if (c == defltc.t_suspc || c == defltc.t_dsuspc) {
47323530Sbloom 				bol = 1;
47423530Sbloom 				echo(c);
47523530Sbloom 				stop(c);
47623530Sbloom 				continue;
47723530Sbloom 			}
47836511Skfall 			if (c != cmdchar) {
47936511Skfall #ifdef	KERBEROS
48036511Skfall 				if(encrypt) {
48136511Skfall 					(void) des_write(
48236511Skfall 						rem,
48336511Skfall 						&cmdchar,
48436511Skfall 						1
48536511Skfall 					);
48636511Skfall 				} else
48736511Skfall #endif
48836511Skfall 					(void) write(
48936511Skfall 						rem,
49036511Skfall 						&cmdchar,
49136511Skfall 						1
49236511Skfall 					);
49336511Skfall 			}
4946444Swnj 		}
49536511Skfall 
49636511Skfall #ifdef	KERBEROS
49736511Skfall 		if(encrypt) {
49836511Skfall 			if (des_write(rem, &c, 1) == 0) {
49936511Skfall 				prf("line gone");
50036511Skfall 				break;
50136511Skfall 			}
50236511Skfall 		} else
50336511Skfall #endif
50436511Skfall 			if (write(rem, &c, 1) == 0) {
50536511Skfall 				prf("line gone");
50636511Skfall 				break;
50736511Skfall 			}
50823530Sbloom 		bol = c == defkill || c == deftc.t_eofc ||
50925424Skarels 		    c == deftc.t_intrc || c == defltc.t_suspc ||
51023530Sbloom 		    c == '\r' || c == '\n';
5116444Swnj 	}
5126444Swnj }
5136444Swnj 
51423530Sbloom echo(c)
51523530Sbloom register char c;
51623530Sbloom {
51723530Sbloom 	char buf[8];
51823530Sbloom 	register char *p = buf;
51923530Sbloom 
52023530Sbloom 	c &= 0177;
52123530Sbloom 	*p++ = cmdchar;
52223530Sbloom 	if (c < ' ') {
52323530Sbloom 		*p++ = '^';
52423530Sbloom 		*p++ = c + '@';
52523530Sbloom 	} else if (c == 0177) {
52623530Sbloom 		*p++ = '^';
52723530Sbloom 		*p++ = '?';
52823530Sbloom 	} else
52923530Sbloom 		*p++ = c;
53023530Sbloom 	*p++ = '\r';
53123530Sbloom 	*p++ = '\n';
53229729Smckusick 	(void) write(1, buf, p - buf);
53323530Sbloom }
53423530Sbloom 
53518358Ssam stop(cmdc)
53618358Ssam 	char cmdc;
53718358Ssam {
53818358Ssam 	mode(0);
53929729Smckusick 	(void) signal(SIGCHLD, SIG_IGN);
54029729Smckusick 	(void) kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP);
54129729Smckusick 	(void) signal(SIGCHLD, catchild);
54218358Ssam 	mode(1);
54318358Ssam 	sigwinch();			/* check for size changes */
54418358Ssam }
54518358Ssam 
54618358Ssam sigwinch()
54718358Ssam {
54818358Ssam 	struct winsize ws;
54918358Ssam 
55029729Smckusick 	if (dosigwinch && get_window_size(0, &ws) == 0 &&
55118358Ssam 	    bcmp(&ws, &winsize, sizeof (ws))) {
55218358Ssam 		winsize = ws;
55324726Smckusick 		sendwindow();
55418358Ssam 	}
55518358Ssam }
55618358Ssam 
55724726Smckusick /*
55824726Smckusick  * Send the window size to the server via the magic escape
55924726Smckusick  */
56024726Smckusick sendwindow()
56124726Smckusick {
56224726Smckusick 	char obuf[4 + sizeof (struct winsize)];
56324726Smckusick 	struct winsize *wp = (struct winsize *)(obuf+4);
56424726Smckusick 
56524726Smckusick 	obuf[0] = 0377;
56624726Smckusick 	obuf[1] = 0377;
56724726Smckusick 	obuf[2] = 's';
56824726Smckusick 	obuf[3] = 's';
56924726Smckusick 	wp->ws_row = htons(winsize.ws_row);
57024726Smckusick 	wp->ws_col = htons(winsize.ws_col);
57124726Smckusick 	wp->ws_xpixel = htons(winsize.ws_xpixel);
57224726Smckusick 	wp->ws_ypixel = htons(winsize.ws_ypixel);
57336511Skfall 
57436511Skfall #ifdef	KERBEROS
57536511Skfall 	if(encrypt)
57636511Skfall 		(void) des_write(rem, obuf, sizeof(obuf));
57736511Skfall 	else
57836511Skfall #endif
57936511Skfall 		(void) write(rem, obuf, sizeof(obuf));
58024726Smckusick }
58124726Smckusick 
58225424Skarels /*
58325424Skarels  * reader: read from remote: line -> 1
58425424Skarels  */
58525424Skarels #define	READING	1
58625424Skarels #define	WRITING	2
58725424Skarels 
58825424Skarels char	rcvbuf[8 * 1024];
58925424Skarels int	rcvcnt;
59025424Skarels int	rcvstate;
59126981Skarels int	ppid;
59225424Skarels jmp_buf	rcvtop;
59325424Skarels 
5946444Swnj oob()
5956444Swnj {
59625424Skarels 	int out = FWRITE, atmark, n;
59725424Skarels 	int rcvd = 0;
5989365Ssam 	char waste[BUFSIZ], mark;
59924726Smckusick 	struct sgttyb sb;
6006444Swnj 
60125424Skarels 	while (recv(rem, &mark, 1, MSG_OOB) < 0)
60225424Skarels 		switch (errno) {
60325424Skarels 
60425424Skarels 		case EWOULDBLOCK:
60525424Skarels 			/*
60625424Skarels 			 * Urgent data not here yet.
60725424Skarels 			 * It may not be possible to send it yet
60825424Skarels 			 * if we are blocked for output
60925424Skarels 			 * and our input buffer is full.
61025424Skarels 			 */
61125424Skarels 			if (rcvcnt < sizeof(rcvbuf)) {
61225424Skarels 				n = read(rem, rcvbuf + rcvcnt,
61325424Skarels 					sizeof(rcvbuf) - rcvcnt);
61425424Skarels 				if (n <= 0)
61525424Skarels 					return;
61625424Skarels 				rcvd += n;
61725424Skarels 			} else {
61825424Skarels 				n = read(rem, waste, sizeof(waste));
61925424Skarels 				if (n <= 0)
62025424Skarels 					return;
62125424Skarels 			}
62225424Skarels 			continue;
62325424Skarels 
62425424Skarels 		default:
62525424Skarels 			return;
6266444Swnj 	}
62725424Skarels 	if (mark & TIOCPKT_WINDOW) {
62824726Smckusick 		/*
62924726Smckusick 		 * Let server know about window size changes
63024726Smckusick 		 */
63129729Smckusick 		(void) kill(ppid, SIGUSR1);
63224726Smckusick 	}
63325424Skarels 	if (!eight && (mark & TIOCPKT_NOSTOP)) {
63429729Smckusick 		(void) ioctl(0, TIOCGETP, (char *)&sb);
63524726Smckusick 		sb.sg_flags &= ~CBREAK;
63624726Smckusick 		sb.sg_flags |= RAW;
63729729Smckusick 		(void) ioctl(0, TIOCSETN, (char *)&sb);
63813075Ssam 		notc.t_stopc = -1;
63913075Ssam 		notc.t_startc = -1;
64029729Smckusick 		(void) ioctl(0, TIOCSETC, (char *)&notc);
6416444Swnj 	}
64225424Skarels 	if (!eight && (mark & TIOCPKT_DOSTOP)) {
64329729Smckusick 		(void) ioctl(0, TIOCGETP, (char *)&sb);
64424726Smckusick 		sb.sg_flags &= ~RAW;
64524726Smckusick 		sb.sg_flags |= CBREAK;
64629729Smckusick 		(void) ioctl(0, TIOCSETN, (char *)&sb);
64713075Ssam 		notc.t_stopc = deftc.t_stopc;
64813075Ssam 		notc.t_startc = deftc.t_startc;
64929729Smckusick 		(void) ioctl(0, TIOCSETC, (char *)&notc);
6506444Swnj 	}
65125424Skarels 	if (mark & TIOCPKT_FLUSHWRITE) {
65229729Smckusick 		(void) ioctl(1, TIOCFLUSH, (char *)&out);
65325424Skarels 		for (;;) {
65425424Skarels 			if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
65525424Skarels 				perror("ioctl");
65625424Skarels 				break;
65725424Skarels 			}
65825424Skarels 			if (atmark)
65925424Skarels 				break;
66025424Skarels 			n = read(rem, waste, sizeof (waste));
66125424Skarels 			if (n <= 0)
66225424Skarels 				break;
66325424Skarels 		}
66425424Skarels 		/*
66525424Skarels 		 * Don't want any pending data to be output,
66625424Skarels 		 * so clear the recv buffer.
66725424Skarels 		 * If we were hanging on a write when interrupted,
66825424Skarels 		 * don't want it to restart.  If we were reading,
66925424Skarels 		 * restart anyway.
67025424Skarels 		 */
67125424Skarels 		rcvcnt = 0;
67225424Skarels 		longjmp(rcvtop, 1);
67325424Skarels 	}
67429729Smckusick 
67525424Skarels 	/*
67629729Smckusick 	 * oob does not do FLUSHREAD (alas!)
67729729Smckusick 	 */
67829729Smckusick 
67929729Smckusick 	/*
68025424Skarels 	 * If we filled the receive buffer while a read was pending,
68125424Skarels 	 * longjmp to the top to restart appropriately.  Don't abort
68225424Skarels 	 * a pending write, however, or we won't know how much was written.
68325424Skarels 	 */
68425424Skarels 	if (rcvd && rcvstate == READING)
68525424Skarels 		longjmp(rcvtop, 1);
6866444Swnj }
6876444Swnj 
6889365Ssam /*
6899365Ssam  * reader: read from remote: line -> 1
6909365Ssam  */
69129729Smckusick reader(oldmask)
69229729Smckusick 	int oldmask;
6936444Swnj {
69426981Skarels #if !defined(BSD) || BSD < 43
69526981Skarels 	int pid = -getpid();
69626981Skarels #else
69725424Skarels 	int pid = getpid();
69826981Skarels #endif
69925424Skarels 	int n, remaining;
70025424Skarels 	char *bufp = rcvbuf;
7016444Swnj 
70229729Smckusick 	(void) signal(SIGTTOU, SIG_IGN);
70329729Smckusick 	(void) signal(SIGURG, oob);
70426981Skarels 	ppid = getppid();
70529729Smckusick 	(void) fcntl(rem, F_SETOWN, pid);
70625424Skarels 	(void) setjmp(rcvtop);
70729729Smckusick 	(void) sigsetmask(oldmask);
7086444Swnj 	for (;;) {
70925424Skarels 		while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) {
71025424Skarels 			rcvstate = WRITING;
71125424Skarels 			n = write(1, bufp, remaining);
71225424Skarels 			if (n < 0) {
71325424Skarels 				if (errno != EINTR)
71426189Slepreau 					return (-1);
71525424Skarels 				continue;
71625424Skarels 			}
71725424Skarels 			bufp += n;
71825424Skarels 		}
71925424Skarels 		bufp = rcvbuf;
72025424Skarels 		rcvcnt = 0;
72125424Skarels 		rcvstate = READING;
72236511Skfall 
72336511Skfall #ifdef	KERBEROS
72436511Skfall 		if(encrypt)
72536511Skfall 			rcvcnt = des_read(rem, rcvbuf, sizeof(rcvbuf));
72636511Skfall 		else
72736511Skfall #endif
72836511Skfall 			rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf));
72925424Skarels 		if (rcvcnt == 0)
73025424Skarels 			return (0);
73125424Skarels 		if (rcvcnt < 0) {
7329365Ssam 			if (errno == EINTR)
7336444Swnj 				continue;
73426981Skarels 			perror("read");
73525424Skarels 			return (-1);
7366444Swnj 		}
7376444Swnj 	}
7386444Swnj }
7396444Swnj 
7406444Swnj mode(f)
7416444Swnj {
74213075Ssam 	struct tchars *tc;
74313075Ssam 	struct ltchars *ltc;
74413075Ssam 	struct sgttyb sb;
74521583Sbloom 	int	lflags;
7469365Ssam 
74729729Smckusick 	(void) ioctl(0, TIOCGETP, (char *)&sb);
74829729Smckusick 	(void) ioctl(0, TIOCLGET, (char *)&lflags);
7499962Ssam 	switch (f) {
7509962Ssam 
7519962Ssam 	case 0:
75213075Ssam 		sb.sg_flags &= ~(CBREAK|RAW|TBDELAY);
75313075Ssam 		sb.sg_flags |= defflags|tabflag;
7549962Ssam 		tc = &deftc;
75513075Ssam 		ltc = &defltc;
75613075Ssam 		sb.sg_kill = defkill;
75713075Ssam 		sb.sg_erase = deferase;
75821583Sbloom 		lflags = deflflags;
7599962Ssam 		break;
7609962Ssam 
7619962Ssam 	case 1:
76213075Ssam 		sb.sg_flags |= (eight ? RAW : CBREAK);
76313075Ssam 		sb.sg_flags &= ~defflags;
76412155Ssam 		/* preserve tab delays, but turn off XTABS */
76513075Ssam 		if ((sb.sg_flags & TBDELAY) == XTABS)
76613075Ssam 			sb.sg_flags &= ~TBDELAY;
7679962Ssam 		tc = &notc;
76813075Ssam 		ltc = &noltc;
76913075Ssam 		sb.sg_kill = sb.sg_erase = -1;
77021583Sbloom 		if (litout)
77121583Sbloom 			lflags |= LLITOUT;
7729962Ssam 		break;
7739962Ssam 
7749962Ssam 	default:
7759962Ssam 		return;
7766444Swnj 	}
77729729Smckusick 	(void) ioctl(0, TIOCSLTC, (char *)ltc);
77829729Smckusick 	(void) ioctl(0, TIOCSETC, (char *)tc);
77929729Smckusick 	(void) ioctl(0, TIOCSETN, (char *)&sb);
78029729Smckusick 	(void) ioctl(0, TIOCLSET, (char *)&lflags);
7816444Swnj }
7826444Swnj 
7839365Ssam /*VARARGS*/
78424726Smckusick prf(f, a1, a2, a3, a4, a5)
7859365Ssam 	char *f;
7866444Swnj {
78729729Smckusick 
78824726Smckusick 	fprintf(stderr, f, a1, a2, a3, a4, a5);
7896444Swnj 	fprintf(stderr, CRLF);
7906444Swnj }
7916444Swnj 
7929365Ssam lostpeer()
7936444Swnj {
79429729Smckusick 
79529729Smckusick 	(void) signal(SIGPIPE, SIG_IGN);
79612155Ssam 	prf("\007Connection closed.");
79725424Skarels 	done(1);
7986444Swnj }
79936512Skfall 
80036512Skfall old_warning(str)
80136512Skfall 	char	*str;
80236512Skfall {
80336512Skfall 	prf("Warning: %s, using standard rlogin", str);
80436512Skfall }
805