xref: /csrg-svn/usr.bin/rlogin/rlogin.c (revision 40858)
1*40858Sbostic /*-
2*40858Sbostic  * Copyright (c) 1983, 1990 The Regents of the University of California.
335539Sbostic  * All rights reserved.
435539Sbostic  *
5*40858Sbostic %sccs.include.redist.c%
621595Sdist  */
721595Sdist 
86444Swnj #ifndef lint
921595Sdist char copyright[] =
10*40858Sbostic "@(#) Copyright (c) 1983, 1990 The Regents of the University of California.\n\
1121595Sdist  All rights reserved.\n";
1235539Sbostic #endif /* not lint */
136444Swnj 
1421595Sdist #ifndef lint
15*40858Sbostic static char sccsid[] = "@(#)rlogin.c	5.23 (Berkeley) 04/09/90";
1635539Sbostic #endif /* not lint */
1721595Sdist 
1812990Ssam /*
19*40858Sbostic  * $Source: mit/rlogin/RCS/rlogin.c,v $
20*40858Sbostic  * $Header: mit/rlogin/RCS/rlogin.c,v 5.2 89/07/26 12:11:21 kfall Exp Locker: kfall $
21*40858Sbostic  */
22*40858Sbostic 
23*40858Sbostic /*
2412990Ssam  * rlogin - remote login
2512990Ssam  */
2626981Skarels #include <sys/param.h>
2725424Skarels #include <sys/errno.h>
2824727Smckusick #include <sys/file.h>
296444Swnj #include <sys/socket.h>
30*40858Sbostic #include <sys/signal.h>
3129729Smckusick #include <sys/time.h>
3229729Smckusick #include <sys/resource.h>
3313620Ssam #include <sys/wait.h>
349365Ssam 
359207Ssam #include <netinet/in.h>
36*40858Sbostic #include <netdb.h>
379365Ssam 
389365Ssam #include <sgtty.h>
39*40858Sbostic #include <setjmp.h>
406444Swnj #include <errno.h>
41*40858Sbostic #include <varargs.h>
426444Swnj #include <pwd.h>
43*40858Sbostic #include <stdio.h>
44*40858Sbostic #include <unistd.h>
45*40858Sbostic #include <strings.h>
466444Swnj 
47*40858Sbostic #ifdef KERBEROS
4840683Sbostic #include <kerberosIV/krb.h>
4936511Skfall 
50*40858Sbostic CREDENTIALS cred;
51*40858Sbostic Key_schedule schedule;
52*40858Sbostic int use_kerberos = 1, encrypt;
53*40858Sbostic char dst_realm_buf[REALM_SZ], *dest_realm = NULL;
54*40858Sbostic extern char *krb_realmofhost();
55*40858Sbostic #endif
5624726Smckusick 
57*40858Sbostic #ifndef TIOCPKT_WINDOW
58*40858Sbostic #define	TIOCPKT_WINDOW	0x80
59*40858Sbostic #endif
6029729Smckusick 
61*40858Sbostic /* concession to Sun */
62*40858Sbostic #ifndef SIGUSR1
63*40858Sbostic #define	SIGUSR1	30
6426981Skarels #endif
65*40858Sbostic 
66*40858Sbostic extern int errno;
67*40858Sbostic int eight, litout, rem;
68*40858Sbostic char cmdchar;
69*40858Sbostic char *speeds[] = {
70*40858Sbostic 	"0", "50", "75", "110", "134", "150", "200", "300", "600", "1200",
71*40858Sbostic 	"1800", "2400", "4800", "9600", "19200", "38400"
72*40858Sbostic };
73*40858Sbostic 
7426981Skarels #ifdef sun
7526981Skarels struct winsize {
7626981Skarels 	unsigned short ws_row, ws_col;
7726981Skarels 	unsigned short ws_xpixel, ws_ypixel;
7826981Skarels };
79*40858Sbostic #endif
8018358Ssam struct	winsize winsize;
816444Swnj 
82*40858Sbostic #ifndef sun
83*40858Sbostic #define	get_window_size(fd, wp)	ioctl(fd, TIOCGWINSZ, wp)
84*40858Sbostic #endif
8529729Smckusick 
86*40858Sbostic void exit();
8729729Smckusick 
886444Swnj main(argc, argv)
896444Swnj 	int argc;
906444Swnj 	char **argv;
916444Swnj {
92*40858Sbostic 	extern char *optarg;
93*40858Sbostic 	extern int optind;
94*40858Sbostic 	struct passwd *pw;
95*40858Sbostic 	struct servent *sp;
966444Swnj 	struct sgttyb ttyb;
97*40858Sbostic 	long omask;
98*40858Sbostic 	int argoff, ch, dflag, one, uid;
99*40858Sbostic 	char *host, *p, *user, term[1024];
100*40858Sbostic 	void lostpeer();
101*40858Sbostic 	char *getenv();
1026444Swnj 
103*40858Sbostic 	argoff = dflag = 0;
104*40858Sbostic 	one = 1;
105*40858Sbostic 	host = user = NULL;
106*40858Sbostic 	cmdchar = '~';
107*40858Sbostic 
108*40858Sbostic 	if (p = rindex(argv[0], '/'))
109*40858Sbostic 		++p;
1106444Swnj 	else
111*40858Sbostic 		p = argv[0];
112*40858Sbostic 
113*40858Sbostic 	if (strcmp(p, "rlogin"))
114*40858Sbostic 		host = p;
115*40858Sbostic 
116*40858Sbostic 	/* handle "rlogin host flags" */
117*40858Sbostic 	if (!host && argc > 2 && argv[1][0] != '-') {
118*40858Sbostic 		host = argv[1];
119*40858Sbostic 		argoff = 1;
1206444Swnj 	}
12136511Skfall 
122*40858Sbostic #ifdef KERBEROS
123*40858Sbostic #define	OPTIONS	"8Lde:k:l:x"
124*40858Sbostic #else
125*40858Sbostic #define	OPTIONS	"8Lde:l:"
126*40858Sbostic #endif
127*40858Sbostic 	while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF)
128*40858Sbostic 		switch(ch) {
129*40858Sbostic 		case '8':
130*40858Sbostic 			eight = 1;
131*40858Sbostic 			break;
132*40858Sbostic 		case 'L':
133*40858Sbostic 			litout = 1;
134*40858Sbostic 			break;
135*40858Sbostic 		case 'd':
136*40858Sbostic 			dflag = 1;
137*40858Sbostic 			break;
138*40858Sbostic 		case 'e':
139*40858Sbostic 			cmdchar = optarg[0];
140*40858Sbostic 			break;
141*40858Sbostic #ifdef KERBEROS
142*40858Sbostic 		case 'k':
143*40858Sbostic 			dest_realm = dst_realm_buf;
144*40858Sbostic 			(void)strncpy(dest_realm, optarg, REALM_SZ);
145*40858Sbostic 			break;
146*40858Sbostic #endif
147*40858Sbostic 		case 'l':
148*40858Sbostic 			user = optarg;
149*40858Sbostic 			break;
150*40858Sbostic #ifdef KERBEROS
151*40858Sbostic 		case 'x':
152*40858Sbostic 			encrypt = 1;
153*40858Sbostic 			des_set_key(cred.session, schedule);
154*40858Sbostic 			break;
155*40858Sbostic #endif
156*40858Sbostic 		case '?':
157*40858Sbostic 		default:
158*40858Sbostic 			usage();
15936524Skfall 		}
160*40858Sbostic 	optind += argoff;
161*40858Sbostic 	argc -= optind;
162*40858Sbostic 	argv += optind;
16336524Skfall 
164*40858Sbostic 	/* if haven't gotten a host yet, do so */
165*40858Sbostic 	if (!host && !(host = *argv++))
166*40858Sbostic 		usage();
16736511Skfall 
168*40858Sbostic 	if (*argv)
169*40858Sbostic 		usage();
170*40858Sbostic 
171*40858Sbostic 	if (!(pw = getpwuid(uid = getuid()))) {
172*40858Sbostic 		(void)fprintf(stderr, "rlogin: unknown user id.\n");
1736444Swnj 		exit(1);
1746444Swnj 	}
175*40858Sbostic 	if (!user)
176*40858Sbostic 		user = pw->pw_name;
177*40858Sbostic 
178*40858Sbostic #ifdef KERBEROS
17936716Skfall 	sp = getservbyname((encrypt ? "eklogin" : "klogin"), "tcp");
18036512Skfall 	if(sp == NULL) {
18136512Skfall 		use_kerberos = 0;
182*40858Sbostic 		warning("can't get entry for %s/tcp service",
183*40858Sbostic 		    encrypt ? "eklogin" : "klogin");
18436512Skfall 		sp = getservbyname("login", "tcp");
18536512Skfall 	}
18636512Skfall #else
1879365Ssam 	sp = getservbyname("login", "tcp");
18836512Skfall #endif
189*40858Sbostic 	if (sp == NULL) {
190*40858Sbostic 		(void)fprintf(stderr, "rlogin: login/tcp: unknown service.\n");
191*40858Sbostic 		exit(1);
1929365Ssam 	}
193*40858Sbostic 
194*40858Sbostic 	(void)strcpy(term, (p = getenv("TERM")) ? p : "network");
19518358Ssam 	if (ioctl(0, TIOCGETP, &ttyb) == 0) {
196*40858Sbostic 		(void)strcat(term, "/");
197*40858Sbostic 		(void)strcat(term, speeds[ttyb.sg_ospeed]);
1986444Swnj 	}
199*40858Sbostic 
200*40858Sbostic 	(void)get_window_size(0, &winsize);
201*40858Sbostic 
202*40858Sbostic 	(void)signal(SIGPIPE, lostpeer);
20329729Smckusick 	/* will use SIGUSR1 for window size hack, so hold it off */
204*40858Sbostic 	omask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1));
20536511Skfall 
206*40858Sbostic #ifdef KERBEROS
20736512Skfall try_connect:
208*40858Sbostic 	if (use_kerberos) {
20936512Skfall 		rem = KSUCCESS;
210*40858Sbostic 		errno = 0;
21138728Skfall 		if (dest_realm == NULL)
21238728Skfall 			dest_realm = krb_realmofhost(host);
21338728Skfall 
214*40858Sbostic 		if (encrypt)
215*40858Sbostic 			rem = krcmd_mutual(&host, sp->s_port, user, term, 0,
216*40858Sbostic 			    dest_realm, &cred, schedule);
217*40858Sbostic 		else
218*40858Sbostic 			rem = krcmd(&host, sp->s_port, user, term, 0,
219*40858Sbostic 			    dest_realm);
22038728Skfall 		if (rem < 0) {
22136512Skfall 			use_kerberos = 0;
22236628Skfall 			sp = getservbyname("login", "tcp");
223*40858Sbostic 			if (sp == NULL) {
224*40858Sbostic 				(void)fprintf(stderr,
225*40858Sbostic 				    "rlogin: unknown service login/tcp.\n");
22636628Skfall 				exit(1);
22736628Skfall 			}
22838728Skfall 			if (errno == ECONNREFUSED)
229*40858Sbostic 				warning("remote host doesn't support Kerberos");
23038728Skfall 			if (errno == ENOENT)
231*40858Sbostic 				warning("can't provide Kerberos auth data");
23236512Skfall 			goto try_connect;
23336512Skfall 		}
23436511Skfall 	} else {
235*40858Sbostic 		if (encrypt) {
236*40858Sbostic 			(void)fprintf(stderr,
237*40858Sbostic 			    "rlogin: the -x flag requires Kerberos authentication.\n");
23836512Skfall 			exit(1);
23936512Skfall 		}
240*40858Sbostic 		rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0);
24136511Skfall 	}
24236512Skfall #else
243*40858Sbostic 	rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0);
24436512Skfall #endif
24536511Skfall 
246*40858Sbostic 	if (rem < 0)
24736511Skfall 		exit(1);
24836511Skfall 
249*40858Sbostic 	if (dflag &&
250*40858Sbostic 	    setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0)
251*40858Sbostic 		(void)fprintf(stderr, "rlogin: setsockopt: %s.\n",
252*40858Sbostic 		    strerror(errno));
253*40858Sbostic 
254*40858Sbostic 	(void)setuid(uid);
255*40858Sbostic 	doit(omask);
2569365Ssam 	/*NOTREACHED*/
2576444Swnj }
2586444Swnj 
259*40858Sbostic int child, defflags, deflflags, tabflag;
260*40858Sbostic char deferase, defkill;
261*40858Sbostic struct tchars deftc;
262*40858Sbostic struct ltchars defltc;
263*40858Sbostic struct tchars notc = { -1, -1, -1, -1, -1, -1 };
264*40858Sbostic struct ltchars noltc = { -1, -1, -1, -1, -1, -1 };
2656444Swnj 
266*40858Sbostic doit(omask)
267*40858Sbostic 	long omask;
2686444Swnj {
26913075Ssam 	struct sgttyb sb;
270*40858Sbostic 	void catch_child(), copytochild(), exit(), writeroob();
2716444Swnj 
272*40858Sbostic 	(void)ioctl(0, TIOCGETP, (char *)&sb);
27313075Ssam 	defflags = sb.sg_flags;
27412155Ssam 	tabflag = defflags & TBDELAY;
2759962Ssam 	defflags &= ECHO | CRMOD;
27613075Ssam 	deferase = sb.sg_erase;
27713075Ssam 	defkill = sb.sg_kill;
278*40858Sbostic 	(void)ioctl(0, TIOCLGET, (char *)&deflflags);
279*40858Sbostic 	(void)ioctl(0, TIOCGETC, (char *)&deftc);
28013075Ssam 	notc.t_startc = deftc.t_startc;
28113075Ssam 	notc.t_stopc = deftc.t_stopc;
282*40858Sbostic 	(void)ioctl(0, TIOCGLTC, (char *)&defltc);
283*40858Sbostic 	(void)signal(SIGINT, SIG_IGN);
28429729Smckusick 	setsignal(SIGHUP, exit);
28529729Smckusick 	setsignal(SIGQUIT, exit);
2869365Ssam 	child = fork();
2879365Ssam 	if (child == -1) {
288*40858Sbostic 		(void)fprintf(stderr, "rlogin: fork: %s.\n", strerror(errno));
28925424Skarels 		done(1);
2909365Ssam 	}
2919365Ssam 	if (child == 0) {
29224726Smckusick 		mode(1);
293*40858Sbostic 		if (reader(omask) == 0) {
294*40858Sbostic 			msg("connection closed.");
29525424Skarels 			exit(0);
29625424Skarels 		}
29712155Ssam 		sleep(1);
298*40858Sbostic 		msg("\007connection closed.");
299*40858Sbostic 		exit(1);
3006444Swnj 	}
30129729Smckusick 
30229729Smckusick 	/*
303*40858Sbostic 	 * We may still own the socket, and may have a pending SIGURG (or might
304*40858Sbostic 	 * receive one soon) that we really want to send to the reader.  Set a
305*40858Sbostic 	 * trap that simply copies such signals to the child.
30629729Smckusick 	 */
307*40858Sbostic 	(void)signal(SIGURG, copytochild);
308*40858Sbostic 	(void)signal(SIGUSR1, writeroob);
309*40858Sbostic 	(void)sigsetmask(omask);
310*40858Sbostic 	(void)signal(SIGCHLD, catch_child);
3119365Ssam 	writer();
312*40858Sbostic 	msg("closed connection.");
31325424Skarels 	done(0);
3146444Swnj }
3156444Swnj 
316*40858Sbostic /* trap a signal, unless it is being ignored. */
31729729Smckusick setsignal(sig, act)
318*40858Sbostic 	int sig;
319*40858Sbostic 	void (*act)();
32029729Smckusick {
32129729Smckusick 	int omask = sigblock(sigmask(sig));
32229729Smckusick 
32329729Smckusick 	if (signal(sig, act) == SIG_IGN)
324*40858Sbostic 		(void)signal(sig, SIG_IGN);
325*40858Sbostic 	(void)sigsetmask(omask);
32629729Smckusick }
32729729Smckusick 
32825424Skarels done(status)
32925424Skarels 	int status;
3306444Swnj {
33129729Smckusick 	int w;
3326444Swnj 
3336444Swnj 	mode(0);
33429729Smckusick 	if (child > 0) {
335*40858Sbostic 		/* make sure catch_child does not snap it up */
336*40858Sbostic 		(void)signal(SIGCHLD, SIG_DFL);
33729729Smckusick 		if (kill(child, SIGKILL) >= 0)
338*40858Sbostic 			while ((w = wait((union wait *)0)) > 0 && w != child);
33929729Smckusick 	}
34025424Skarels 	exit(status);
3416444Swnj }
3426444Swnj 
343*40858Sbostic int dosigwinch;
34429729Smckusick 
34529729Smckusick /*
34624726Smckusick  * This is called when the reader process gets the out-of-band (urgent)
34724726Smckusick  * request to turn on the window-changing protocol.
34824726Smckusick  */
349*40858Sbostic void
35024726Smckusick writeroob()
35124726Smckusick {
352*40858Sbostic 	void sigwinch();
35324726Smckusick 
35425341Smckusick 	if (dosigwinch == 0) {
35524919Smckusick 		sendwindow();
356*40858Sbostic 		(void)signal(SIGWINCH, sigwinch);
35725341Smckusick 	}
35824726Smckusick 	dosigwinch = 1;
35924726Smckusick }
36024726Smckusick 
361*40858Sbostic void
362*40858Sbostic catch_child()
36311803Sedward {
36411803Sedward 	union wait status;
36511803Sedward 	int pid;
36611803Sedward 
367*40858Sbostic 	for (;;) {
368*40858Sbostic 		pid = wait3(&status, WNOHANG|WUNTRACED, (struct rusage *)0);
369*40858Sbostic 		if (pid == 0)
370*40858Sbostic 			return;
371*40858Sbostic 		/* if the child (reader) dies, just quit */
372*40858Sbostic 		if (pid < 0 || pid == child && !WIFSTOPPED(status))
373*40858Sbostic 			done((int)(status.w_termsig | status.w_retcode));
374*40858Sbostic 	}
375*40858Sbostic 	/* NOTREACHED */
37611803Sedward }
37711803Sedward 
3786444Swnj /*
3799365Ssam  * writer: write to remote: 0 -> line.
3809365Ssam  * ~.	terminate
3819365Ssam  * ~^Z	suspend rlogin process.
38210415Ssam  * ~^Y  suspend rlogin process, but leave reader alone.
3836444Swnj  */
3849365Ssam writer()
3856444Swnj {
38623530Sbloom 	char c;
387*40858Sbostic 	register int bol, local, n;
3886444Swnj 
389*40858Sbostic 	bol = 1;			/* beginning of line */
390*40858Sbostic 	local = 0;
39111803Sedward 	for (;;) {
392*40858Sbostic 		n = read(STDIN_FILENO, &c, 1);
39318358Ssam 		if (n <= 0) {
39418358Ssam 			if (n < 0 && errno == EINTR)
39518358Ssam 				continue;
39611803Sedward 			break;
39718358Ssam 		}
3989365Ssam 		/*
399*40858Sbostic 		 * If we're at the beginning of the line and recognize a
400*40858Sbostic 		 * command character, then we echo locally.  Otherwise,
401*40858Sbostic 		 * characters are echo'd remotely.  If the command character
402*40858Sbostic 		 * is doubled, this acts as a force and local echo is
403*40858Sbostic 		 * suppressed.
4049365Ssam 		 */
40523530Sbloom 		if (bol) {
40623530Sbloom 			bol = 0;
40723530Sbloom 			if (c == cmdchar) {
40823530Sbloom 				bol = 0;
40923530Sbloom 				local = 1;
41023530Sbloom 				continue;
4116444Swnj 			}
41223530Sbloom 		} else if (local) {
41323530Sbloom 			local = 0;
41423530Sbloom 			if (c == '.' || c == deftc.t_eofc) {
41523530Sbloom 				echo(c);
41623530Sbloom 				break;
4176444Swnj 			}
41823530Sbloom 			if (c == defltc.t_suspc || c == defltc.t_dsuspc) {
41923530Sbloom 				bol = 1;
42023530Sbloom 				echo(c);
42123530Sbloom 				stop(c);
42223530Sbloom 				continue;
42323530Sbloom 			}
42436511Skfall 			if (c != cmdchar) {
425*40858Sbostic #ifdef KERBEROS
426*40858Sbostic 				if (encrypt) {
427*40858Sbostic 					(void)des_write(rem, &cmdchar, 1);
42836511Skfall 				} else
42936511Skfall #endif
430*40858Sbostic 					(void)write(rem, &cmdchar, 1);
43136511Skfall 			}
4326444Swnj 		}
43336511Skfall 
434*40858Sbostic #ifdef KERBEROS
435*40858Sbostic 		if (encrypt) {
43636511Skfall 			if (des_write(rem, &c, 1) == 0) {
437*40858Sbostic 				msg("line gone");
43836511Skfall 				break;
43936511Skfall 			}
44036511Skfall 		} else
44136511Skfall #endif
44236511Skfall 			if (write(rem, &c, 1) == 0) {
443*40858Sbostic 				msg("line gone");
44436511Skfall 				break;
44536511Skfall 			}
44623530Sbloom 		bol = c == defkill || c == deftc.t_eofc ||
44725424Skarels 		    c == deftc.t_intrc || c == defltc.t_suspc ||
44823530Sbloom 		    c == '\r' || c == '\n';
4496444Swnj 	}
4506444Swnj }
4516444Swnj 
45223530Sbloom echo(c)
45323530Sbloom register char c;
45423530Sbloom {
455*40858Sbostic 	register char *p;
45623530Sbloom 	char buf[8];
45723530Sbloom 
458*40858Sbostic 	p = buf;
45923530Sbloom 	c &= 0177;
46023530Sbloom 	*p++ = cmdchar;
46123530Sbloom 	if (c < ' ') {
46223530Sbloom 		*p++ = '^';
46323530Sbloom 		*p++ = c + '@';
46423530Sbloom 	} else if (c == 0177) {
46523530Sbloom 		*p++ = '^';
46623530Sbloom 		*p++ = '?';
46723530Sbloom 	} else
46823530Sbloom 		*p++ = c;
46923530Sbloom 	*p++ = '\r';
47023530Sbloom 	*p++ = '\n';
471*40858Sbostic 	(void)write(1, buf, p - buf);
47223530Sbloom }
47323530Sbloom 
47418358Ssam stop(cmdc)
47518358Ssam 	char cmdc;
47618358Ssam {
47718358Ssam 	mode(0);
478*40858Sbostic 	(void)signal(SIGCHLD, SIG_IGN);
479*40858Sbostic 	(void)kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP);
480*40858Sbostic 	(void)signal(SIGCHLD, catch_child);
48118358Ssam 	mode(1);
48218358Ssam 	sigwinch();			/* check for size changes */
48318358Ssam }
48418358Ssam 
485*40858Sbostic void
48618358Ssam sigwinch()
48718358Ssam {
48818358Ssam 	struct winsize ws;
48918358Ssam 
49029729Smckusick 	if (dosigwinch && get_window_size(0, &ws) == 0 &&
491*40858Sbostic 	    bcmp(&ws, &winsize, sizeof(ws))) {
49218358Ssam 		winsize = ws;
49324726Smckusick 		sendwindow();
49418358Ssam 	}
49518358Ssam }
49618358Ssam 
49724726Smckusick /*
49824726Smckusick  * Send the window size to the server via the magic escape
49924726Smckusick  */
50024726Smckusick sendwindow()
50124726Smckusick {
502*40858Sbostic 	struct winsize *wp;
50324726Smckusick 	char obuf[4 + sizeof (struct winsize)];
50424726Smckusick 
505*40858Sbostic 	wp = (struct winsize *)(obuf+4);
50624726Smckusick 	obuf[0] = 0377;
50724726Smckusick 	obuf[1] = 0377;
50824726Smckusick 	obuf[2] = 's';
50924726Smckusick 	obuf[3] = 's';
51024726Smckusick 	wp->ws_row = htons(winsize.ws_row);
51124726Smckusick 	wp->ws_col = htons(winsize.ws_col);
51224726Smckusick 	wp->ws_xpixel = htons(winsize.ws_xpixel);
51324726Smckusick 	wp->ws_ypixel = htons(winsize.ws_ypixel);
51436511Skfall 
515*40858Sbostic #ifdef KERBEROS
51636511Skfall 	if(encrypt)
517*40858Sbostic 		(void)des_write(rem, obuf, sizeof(obuf));
51836511Skfall 	else
51936511Skfall #endif
520*40858Sbostic 		(void)write(rem, obuf, sizeof(obuf));
52124726Smckusick }
52224726Smckusick 
52325424Skarels /*
52425424Skarels  * reader: read from remote: line -> 1
52525424Skarels  */
52625424Skarels #define	READING	1
52725424Skarels #define	WRITING	2
52825424Skarels 
529*40858Sbostic jmp_buf rcvtop;
530*40858Sbostic int ppid, rcvcnt, rcvstate;
531*40858Sbostic char rcvbuf[8 * 1024];
53225424Skarels 
533*40858Sbostic void
5346444Swnj oob()
5356444Swnj {
536*40858Sbostic 	struct sgttyb sb;
537*40858Sbostic 	int atmark, n, out, rcvd;
5389365Ssam 	char waste[BUFSIZ], mark;
5396444Swnj 
540*40858Sbostic 	out = FWRITE;
541*40858Sbostic 	rcvd = 0;
54225424Skarels 	while (recv(rem, &mark, 1, MSG_OOB) < 0)
54325424Skarels 		switch (errno) {
54425424Skarels 		case EWOULDBLOCK:
54525424Skarels 			/*
546*40858Sbostic 			 * Urgent data not here yet.  It may not be possible
547*40858Sbostic 			 * to send it yet if we are blocked for output and
548*40858Sbostic 			 * our input buffer is full.
54925424Skarels 			 */
55025424Skarels 			if (rcvcnt < sizeof(rcvbuf)) {
55125424Skarels 				n = read(rem, rcvbuf + rcvcnt,
552*40858Sbostic 				    sizeof(rcvbuf) - rcvcnt);
55325424Skarels 				if (n <= 0)
55425424Skarels 					return;
55525424Skarels 				rcvd += n;
55625424Skarels 			} else {
55725424Skarels 				n = read(rem, waste, sizeof(waste));
55825424Skarels 				if (n <= 0)
55925424Skarels 					return;
56025424Skarels 			}
56125424Skarels 			continue;
56225424Skarels 		default:
56325424Skarels 			return;
5646444Swnj 	}
56525424Skarels 	if (mark & TIOCPKT_WINDOW) {
566*40858Sbostic 		/* Let server know about window size changes */
567*40858Sbostic 		(void)kill(ppid, SIGUSR1);
56824726Smckusick 	}
56925424Skarels 	if (!eight && (mark & TIOCPKT_NOSTOP)) {
570*40858Sbostic 		(void)ioctl(0, TIOCGETP, (char *)&sb);
57124726Smckusick 		sb.sg_flags &= ~CBREAK;
57224726Smckusick 		sb.sg_flags |= RAW;
573*40858Sbostic 		(void)ioctl(0, TIOCSETN, (char *)&sb);
57413075Ssam 		notc.t_stopc = -1;
57513075Ssam 		notc.t_startc = -1;
576*40858Sbostic 		(void)ioctl(0, TIOCSETC, (char *)&notc);
5776444Swnj 	}
57825424Skarels 	if (!eight && (mark & TIOCPKT_DOSTOP)) {
579*40858Sbostic 		(void)ioctl(0, TIOCGETP, (char *)&sb);
58024726Smckusick 		sb.sg_flags &= ~RAW;
58124726Smckusick 		sb.sg_flags |= CBREAK;
582*40858Sbostic 		(void)ioctl(0, TIOCSETN, (char *)&sb);
58313075Ssam 		notc.t_stopc = deftc.t_stopc;
58413075Ssam 		notc.t_startc = deftc.t_startc;
585*40858Sbostic 		(void)ioctl(0, TIOCSETC, (char *)&notc);
5866444Swnj 	}
58725424Skarels 	if (mark & TIOCPKT_FLUSHWRITE) {
588*40858Sbostic 		(void)ioctl(1, TIOCFLUSH, (char *)&out);
58925424Skarels 		for (;;) {
59025424Skarels 			if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
591*40858Sbostic 				(void)fprintf(stderr, "rlogin: ioctl: %s.\n",
592*40858Sbostic 				    strerror(errno));
59325424Skarels 				break;
59425424Skarels 			}
59525424Skarels 			if (atmark)
59625424Skarels 				break;
59725424Skarels 			n = read(rem, waste, sizeof (waste));
59825424Skarels 			if (n <= 0)
59925424Skarels 				break;
60025424Skarels 		}
60125424Skarels 		/*
602*40858Sbostic 		 * Don't want any pending data to be output, so clear the recv
603*40858Sbostic 		 * buffer.  If we were hanging on a write when interrupted,
604*40858Sbostic 		 * don't want it to restart.  If we were reading, restart
605*40858Sbostic 		 * anyway.
60625424Skarels 		 */
60725424Skarels 		rcvcnt = 0;
60825424Skarels 		longjmp(rcvtop, 1);
60925424Skarels 	}
61029729Smckusick 
611*40858Sbostic 	/* oob does not do FLUSHREAD (alas!) */
61229729Smckusick 
61329729Smckusick 	/*
614*40858Sbostic 	 * If we filled the receive buffer while a read was pending, longjmp
615*40858Sbostic 	 * to the top to restart appropriately.  Don't abort a pending write,
616*40858Sbostic 	 * however, or we won't know how much was written.
61725424Skarels 	 */
61825424Skarels 	if (rcvd && rcvstate == READING)
61925424Skarels 		longjmp(rcvtop, 1);
6206444Swnj }
6216444Swnj 
622*40858Sbostic /* reader: read from remote: line -> 1 */
623*40858Sbostic reader(omask)
624*40858Sbostic 	int omask;
6256444Swnj {
626*40858Sbostic 	void oob();
627*40858Sbostic 
62826981Skarels #if !defined(BSD) || BSD < 43
62926981Skarels 	int pid = -getpid();
63026981Skarels #else
63125424Skarels 	int pid = getpid();
63226981Skarels #endif
63325424Skarels 	int n, remaining;
63425424Skarels 	char *bufp = rcvbuf;
6356444Swnj 
636*40858Sbostic 	(void)signal(SIGTTOU, SIG_IGN);
637*40858Sbostic 	(void)signal(SIGURG, oob);
63826981Skarels 	ppid = getppid();
639*40858Sbostic 	(void)fcntl(rem, F_SETOWN, pid);
640*40858Sbostic 	(void)setjmp(rcvtop);
641*40858Sbostic 	(void)sigsetmask(omask);
6426444Swnj 	for (;;) {
64325424Skarels 		while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) {
64425424Skarels 			rcvstate = WRITING;
64525424Skarels 			n = write(1, bufp, remaining);
64625424Skarels 			if (n < 0) {
64725424Skarels 				if (errno != EINTR)
648*40858Sbostic 					return(-1);
64925424Skarels 				continue;
65025424Skarels 			}
65125424Skarels 			bufp += n;
65225424Skarels 		}
65325424Skarels 		bufp = rcvbuf;
65425424Skarels 		rcvcnt = 0;
65525424Skarels 		rcvstate = READING;
65636511Skfall 
657*40858Sbostic #ifdef KERBEROS
658*40858Sbostic 		if (encrypt)
65936511Skfall 			rcvcnt = des_read(rem, rcvbuf, sizeof(rcvbuf));
66036511Skfall 		else
66136511Skfall #endif
66236511Skfall 			rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf));
66325424Skarels 		if (rcvcnt == 0)
66425424Skarels 			return (0);
66525424Skarels 		if (rcvcnt < 0) {
6669365Ssam 			if (errno == EINTR)
6676444Swnj 				continue;
668*40858Sbostic 			(void)fprintf(stderr, "rlogin: read: %s.\n",
669*40858Sbostic 			    strerror(errno));
670*40858Sbostic 			return(-1);
6716444Swnj 		}
6726444Swnj 	}
6736444Swnj }
6746444Swnj 
6756444Swnj mode(f)
6766444Swnj {
67713075Ssam 	struct ltchars *ltc;
67813075Ssam 	struct sgttyb sb;
679*40858Sbostic 	struct tchars *tc;
680*40858Sbostic 	int lflags;
6819365Ssam 
682*40858Sbostic 	(void)ioctl(0, TIOCGETP, (char *)&sb);
683*40858Sbostic 	(void)ioctl(0, TIOCLGET, (char *)&lflags);
684*40858Sbostic 	switch(f) {
6859962Ssam 	case 0:
68613075Ssam 		sb.sg_flags &= ~(CBREAK|RAW|TBDELAY);
68713075Ssam 		sb.sg_flags |= defflags|tabflag;
6889962Ssam 		tc = &deftc;
68913075Ssam 		ltc = &defltc;
69013075Ssam 		sb.sg_kill = defkill;
69113075Ssam 		sb.sg_erase = deferase;
69221583Sbloom 		lflags = deflflags;
6939962Ssam 		break;
6949962Ssam 	case 1:
69513075Ssam 		sb.sg_flags |= (eight ? RAW : CBREAK);
69613075Ssam 		sb.sg_flags &= ~defflags;
69712155Ssam 		/* preserve tab delays, but turn off XTABS */
69813075Ssam 		if ((sb.sg_flags & TBDELAY) == XTABS)
69913075Ssam 			sb.sg_flags &= ~TBDELAY;
7009962Ssam 		tc = &notc;
70113075Ssam 		ltc = &noltc;
70213075Ssam 		sb.sg_kill = sb.sg_erase = -1;
70321583Sbloom 		if (litout)
70421583Sbloom 			lflags |= LLITOUT;
7059962Ssam 		break;
7069962Ssam 	default:
7079962Ssam 		return;
7086444Swnj 	}
709*40858Sbostic 	(void)ioctl(0, TIOCSLTC, (char *)ltc);
710*40858Sbostic 	(void)ioctl(0, TIOCSETC, (char *)tc);
711*40858Sbostic 	(void)ioctl(0, TIOCSETN, (char *)&sb);
712*40858Sbostic 	(void)ioctl(0, TIOCLSET, (char *)&lflags);
7136444Swnj }
7146444Swnj 
715*40858Sbostic void
716*40858Sbostic lostpeer()
7176444Swnj {
718*40858Sbostic 	(void)signal(SIGPIPE, SIG_IGN);
719*40858Sbostic 	msg("\007connection closed.");
720*40858Sbostic 	done(1);
721*40858Sbostic }
72229729Smckusick 
723*40858Sbostic /* copy SIGURGs to the child process. */
724*40858Sbostic void
725*40858Sbostic copytochild()
726*40858Sbostic {
727*40858Sbostic 	(void)kill(child, SIGURG);
7286444Swnj }
7296444Swnj 
730*40858Sbostic msg(str)
731*40858Sbostic 	char *str;
7326444Swnj {
733*40858Sbostic 	(void)fprintf(stderr, "rlogin: %s\r\n", str);
734*40858Sbostic }
73529729Smckusick 
736*40858Sbostic #ifdef KERBEROS
737*40858Sbostic /* VARARGS */
738*40858Sbostic warning(va_alist)
739*40858Sbostic va_dcl
740*40858Sbostic {
741*40858Sbostic 	va_list ap;
742*40858Sbostic 	char *fmt;
743*40858Sbostic 
744*40858Sbostic 	(void)fprintf(stderr, "rlogin: warning, using standard rlogin: ");
745*40858Sbostic 	va_start(ap);
746*40858Sbostic 	fmt = va_arg(ap, char *);
747*40858Sbostic 	vfprintf(stderr, fmt, ap);
748*40858Sbostic 	va_end(ap);
749*40858Sbostic 	(void)fprintf(stderr, ".\n");
7506444Swnj }
751*40858Sbostic #endif
75236512Skfall 
753*40858Sbostic usage()
75436512Skfall {
755*40858Sbostic 	(void)fprintf(stderr,
756*40858Sbostic 	    "usage: rlogin [ -%s]%s[-e char] [ -l username ] host\n",
757*40858Sbostic #ifdef KERBEROS
758*40858Sbostic 	    "8Lx", " [-k realm] ");
759*40858Sbostic #else
760*40858Sbostic 	    "8L", " ");
761*40858Sbostic #endif
762*40858Sbostic 	exit(1);
76336512Skfall }
764*40858Sbostic 
765*40858Sbostic /*
766*40858Sbostic  * The following routine provides compatibility (such as it is) between 4.2BSD
767*40858Sbostic  * Suns and others.  Suns have only a `ttysize', so we convert it to a winsize.
768*40858Sbostic  */
769*40858Sbostic #ifdef sun
770*40858Sbostic int
771*40858Sbostic get_window_size(fd, wp)
772*40858Sbostic 	int fd;
773*40858Sbostic 	struct winsize *wp;
774*40858Sbostic {
775*40858Sbostic 	struct ttysize ts;
776*40858Sbostic 	int error;
777*40858Sbostic 
778*40858Sbostic 	if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0)
779*40858Sbostic 		return(error);
780*40858Sbostic 	wp->ws_row = ts.ts_lines;
781*40858Sbostic 	wp->ws_col = ts.ts_cols;
782*40858Sbostic 	wp->ws_xpixel = 0;
783*40858Sbostic 	wp->ws_ypixel = 0;
784*40858Sbostic 	return(0);
785*40858Sbostic }
786*40858Sbostic #endif
787