xref: /original-bsd/usr.bin/rlogin/rlogin.c (revision 0842ddeb)
1 /*
2  * Copyright (c) 1983, 1990, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char copyright[] =
10 "@(#) Copyright (c) 1983, 1990, 1993\n\
11 	The Regents of the University of California.  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)rlogin.c	8.4 (Berkeley) 04/29/95";
16 #endif /* not lint */
17 
18 /*
19  * rlogin - remote login
20  */
21 #include <sys/param.h>
22 #include <sys/socket.h>
23 #include <sys/time.h>
24 #include <sys/resource.h>
25 #include <sys/wait.h>
26 #include <sys/ioctl.h>
27 
28 #include <netinet/in.h>
29 #include <netinet/in_systm.h>
30 #include <netinet/ip.h>
31 
32 #include <errno.h>
33 #include <fcntl.h>
34 #include <netdb.h>
35 #include <pwd.h>
36 #include <setjmp.h>
37 #include <termios.h>
38 #include <signal.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <unistd.h>
43 
44 #ifdef __STDC__
45 #include <stdarg.h>
46 #else
47 #include <varargs.h>
48 #endif
49 
50 #ifdef KERBEROS
51 #include <kerberosIV/des.h>
52 #include <kerberosIV/krb.h>
53 
54 #include "krb.h"
55 
56 CREDENTIALS cred;
57 Key_schedule schedule;
58 int use_kerberos = 1, doencrypt;
59 char dst_realm_buf[REALM_SZ], *dest_realm = NULL;
60 #endif
61 
62 #ifndef TIOCPKT_WINDOW
63 #define	TIOCPKT_WINDOW	0x80
64 #endif
65 
66 /* concession to Sun */
67 #ifndef SIGUSR1
68 #define	SIGUSR1	30
69 #endif
70 
71 int eight, litout, rem;
72 
73 int noescape;
74 u_char escapechar = '~';
75 
76 #ifdef OLDSUN
77 struct winsize {
78 	unsigned short ws_row, ws_col;
79 	unsigned short ws_xpixel, ws_ypixel;
80 };
81 #else
82 #define	get_window_size(fd, wp)	ioctl(fd, TIOCGWINSZ, wp)
83 #endif
84 struct	winsize winsize;
85 
86 void		catch_child __P((int));
87 void		copytochild __P((int));
88 __dead void	doit __P((sigset_t *));
89 __dead void	done __P((int));
90 void		echo __P((char));
91 u_int		getescape __P((char *));
92 void		lostpeer __P((int));
93 void		mode __P((int));
94 void		msg __P((char *));
95 void		oob __P((int));
96 int		reader __P((sigset_t *));
97 void		sendwindow __P((void));
98 void		setsignal __P((int));
99 int		speed __P((int));
100 void		sigwinch __P((int));
101 void		stop __P((char));
102 __dead void	usage __P((void));
103 void		writer __P((void));
104 void		writeroob __P((int));
105 
106 #ifdef	KERBEROS
107 void		warning __P((const char *, ...));
108 #endif
109 #ifdef OLDSUN
110 int		get_window_size __P((int, struct winsize *));
111 #endif
112 
113 int
114 main(argc, argv)
115 	int argc;
116 	char *argv[];
117 {
118 	struct passwd *pw;
119 	struct servent *sp;
120 	sigset_t smask;
121 	uid_t uid;
122 	int argoff, ch, dflag, one;
123 	char *host, *p, *user, term[1024];
124 	struct sigaction sa;
125 
126 	argoff = dflag = 0;
127 	one = 1;
128 	host = user = NULL;
129 
130 	if (p = strrchr(argv[0], '/'))
131 		++p;
132 	else
133 		p = argv[0];
134 
135 	if (strcmp(p, "rlogin") != 0)
136 		host = p;
137 
138 	/* handle "rlogin host flags" */
139 	if (!host && argc > 2 && argv[1][0] != '-') {
140 		host = argv[1];
141 		argoff = 1;
142 	}
143 
144 #ifdef KERBEROS
145 #define	OPTIONS	"8EKLde:k:l:x"
146 #else
147 #define	OPTIONS	"8EKLde:l:"
148 #endif
149 	while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF)
150 		switch(ch) {
151 		case '8':
152 			eight = 1;
153 			break;
154 		case 'E':
155 			noescape = 1;
156 			break;
157 		case 'K':
158 #ifdef KERBEROS
159 			use_kerberos = 0;
160 #endif
161 			break;
162 		case 'L':
163 			litout = 1;
164 			break;
165 		case 'd':
166 			dflag = 1;
167 			break;
168 		case 'e':
169 			noescape = 0;
170 			escapechar = getescape(optarg);
171 			break;
172 #ifdef KERBEROS
173 		case 'k':
174 			dest_realm = dst_realm_buf;
175 			(void)strncpy(dest_realm, optarg, REALM_SZ);
176 			break;
177 #endif
178 		case 'l':
179 			user = optarg;
180 			break;
181 #ifdef CRYPT
182 #ifdef KERBEROS
183 		case 'x':
184 			doencrypt = 1;
185 			des_set_key(cred.session, schedule);
186 			break;
187 #endif
188 #endif
189 		case '?':
190 		default:
191 			usage();
192 		}
193 	optind += argoff;
194 	argc -= optind;
195 	argv += optind;
196 
197 	/* if haven't gotten a host yet, do so */
198 	if (!host && !(host = *argv++))
199 		usage();
200 
201 	if (*argv)
202 		usage();
203 
204 	if (!(pw = getpwuid(uid = getuid())))
205 		errx(1, "unknown user id.");
206 	/* Accept user1@host format, though "-l user2" overrides user1 */
207 	p = strchr(host, '@');
208 	if (p) {
209 		*p = '\0';
210 		if (!user && p > host)
211 			user = host;
212 		host = p + 1;
213 		if (*host == '\0')
214 			usage();
215 	}
216 	if (!user)
217 		user = pw->pw_name;
218 
219 	sp = NULL;
220 #ifdef KERBEROS
221 	if (use_kerberos) {
222 		sp = getservbyname((doencrypt ? "eklogin" : "klogin"), "tcp");
223 		if (sp == NULL) {
224 			use_kerberos = 0;
225 			warning("can't get entry for %s/tcp service",
226 			    doencrypt ? "eklogin" : "klogin");
227 		}
228 	}
229 #endif
230 	if (sp == NULL)
231 		sp = getservbyname("login", "tcp");
232 	if (sp == NULL)
233 		errx(1, "login/tcp: unknown service.");
234 
235 	(void)snprintf(term, sizeof(term), "%s/%d",
236 			((p = getenv("TERM")) ? p : "network"),
237 			speed(0));
238 
239 	(void)get_window_size(0, &winsize);
240 
241 	sigemptyset(&sa.sa_mask);
242 	sa.sa_flags = SA_RESTART;
243 	sa.sa_handler = lostpeer;
244 	(void)sigaction(SIGPIPE, &sa, (struct sigaction *) 0);
245 	/* will use SIGUSR1 for window size hack, so hold it off */
246 	sigemptyset(&smask);
247 	sigaddset(&smask, SIGURG);
248 	sigaddset(&smask, SIGUSR1);
249 	(void)sigprocmask(SIG_SETMASK, &smask, &smask);
250 	/*
251 	 * We set SIGURG and SIGUSR1 below so that an
252 	 * incoming signal will be held pending rather than being
253 	 * discarded. Note that these routines will be ready to get
254 	 * a signal by the time that they are unblocked below.
255 	 */
256 	sa.sa_handler = copytochild;
257 	(void)sigaction(SIGURG, &sa, (struct sigaction *) 0);
258 	sa.sa_handler = writeroob;
259 	(void)sigaction(SIGUSR1, &sa, (struct sigaction *) 0);
260 
261 #ifdef KERBEROS
262 try_connect:
263 	if (use_kerberos) {
264 		struct hostent *hp;
265 
266 		/* Fully qualify hostname (needed for krb_realmofhost). */
267 		hp = gethostbyname(host);
268 		if (hp != NULL && !(host = strdup(hp->h_name)))
269 			errx(1, "%s", strerror(ENOMEM));
270 
271 		rem = KSUCCESS;
272 		errno = 0;
273 		if (dest_realm == NULL)
274 			dest_realm = krb_realmofhost(host);
275 
276 #ifdef CRYPT
277 		if (doencrypt)
278 			rem = krcmd_mutual(&host, sp->s_port, user, term, 0,
279 			    dest_realm, &cred, schedule);
280 		else
281 #endif /* CRYPT */
282 			rem = krcmd(&host, sp->s_port, user, term, 0,
283 			    dest_realm);
284 		if (rem < 0) {
285 			use_kerberos = 0;
286 			sp = getservbyname("login", "tcp");
287 			if (sp == NULL)
288 				errx(1, "unknown service login/tcp.");
289 			if (errno == ECONNREFUSED)
290 				warning("remote host doesn't support Kerberos");
291 			if (errno == ENOENT)
292 				warning("can't provide Kerberos auth data");
293 			goto try_connect;
294 		}
295 	} else {
296 #ifdef CRYPT
297 		if (doencrypt)
298 			errx(1, "the -x flag requires Kerberos authentication.");
299 #endif /* CRYPT */
300 		rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0);
301 	}
302 #else
303 	rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0);
304 #endif /* KERBEROS */
305 
306 	if (rem < 0)
307 		exit(1);
308 
309 	if (dflag &&
310 	    setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0)
311 		warn("setsockopt DEBUG (ignored)");
312 	one = IPTOS_LOWDELAY;
313 	if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, sizeof(int)) < 0)
314 		warn("setsockopt TOS (ignored)");
315 
316 	(void)setuid(uid);
317 	doit(&smask);
318 	/*NOTREACHED*/
319 }
320 
321 #if BSD >= 198810
322 int
323 speed(fd)
324 	int fd;
325 {
326 	struct termios tt;
327 
328 	(void)tcgetattr(fd, &tt);
329 
330 	return ((int) cfgetispeed(&tt));
331 }
332 #else
333 int    speeds[] = {	/* for older systems, B0 .. EXTB */
334 	0, 50, 75, 110,
335 	134, 150, 200, 300,
336 	600, 1200, 1800, 2400,
337 	4800, 9600, 19200, 38400
338 };
339 
340 int
341 speed(fd)
342 	int fd;
343 {
344 	struct termios tt;
345 
346 	(void)tcgetattr(fd, &tt);
347 
348 	return (speeds[(int)cfgetispeed(&tt)]);
349 }
350 #endif
351 
352 pid_t child;
353 struct termios deftt;
354 struct termios nott;
355 
356 void
357 doit(smask)
358 	sigset_t *smask;
359 {
360 	int i;
361 	struct sigaction sa;
362 
363 	for (i = 0; i < NCCS; i++)
364 		nott.c_cc[i] = _POSIX_VDISABLE;
365 	tcgetattr(0, &deftt);
366 	nott.c_cc[VSTART] = deftt.c_cc[VSTART];
367 	nott.c_cc[VSTOP] = deftt.c_cc[VSTOP];
368 	sigemptyset(&sa.sa_mask);
369 	sa.sa_flags = SA_RESTART;
370 	sa.sa_handler = SIG_IGN;
371 	(void)sigaction(SIGINT, &sa, (struct sigaction *) 0);
372 	setsignal(SIGHUP);
373 	setsignal(SIGQUIT);
374 	child = fork();
375 	if (child == -1) {
376 		warn("fork");
377 		done(1);
378 	}
379 	if (child == 0) {
380 		mode(1);
381 		if (reader(smask) == 0) {
382 			msg("connection closed.");
383 			exit(0);
384 		}
385 		sleep(1);
386 		msg("\007connection closed.");
387 		exit(1);
388 	}
389 
390 	/*
391 	 * We may still own the socket, and may have a pending SIGURG (or might
392 	 * receive one soon) that we really want to send to the reader.  When
393 	 * one of these comes in, the trap copytochild simply copies such
394 	 * signals to the child. We can now unblock SIGURG and SIGUSR1
395 	 * that were set above.
396 	 */
397 	(void)sigprocmask(SIG_SETMASK, smask, (sigset_t *) 0);
398 	sa.sa_handler = catch_child;
399 	(void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0);
400 	writer();
401 	msg("closed connection.");
402 	done(0);
403 }
404 
405 /* trap a signal, unless it is being ignored. */
406 void
407 setsignal(sig)
408 	int sig;
409 {
410 	struct sigaction sa;
411 	sigset_t sigs;
412 
413 	sigemptyset(&sigs);
414 	sigaddset(&sigs, sig);
415 	sigprocmask(SIG_BLOCK, &sigs, &sigs);
416 
417 	sigemptyset(&sa.sa_mask);
418 	sa.sa_handler = exit;
419 	sa.sa_flags = SA_RESTART;
420 	(void)sigaction(sig, &sa, &sa);
421 	if (sa.sa_handler == SIG_IGN)
422 		(void)sigaction(sig, &sa, (struct sigaction *) 0);
423 
424 	(void)sigprocmask(SIG_SETMASK, &sigs, (sigset_t *) 0);
425 }
426 
427 __dead void
428 done(status)
429 	int status;
430 {
431 	pid_t w;
432 	int wstatus;
433 	struct sigaction sa;
434 
435 	mode(0);
436 	if (child > 0) {
437 		/* make sure catch_child does not snap it up */
438 		sigemptyset(&sa.sa_mask);
439 		sa.sa_handler = SIG_DFL;
440 		sa.sa_flags = 0;
441 		(void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0);
442 		if (kill(child, SIGKILL) >= 0)
443 			while ((w = wait(&wstatus)) > 0 && w != child)
444 				continue;
445 	}
446 	exit(status);
447 }
448 
449 int dosigwinch;
450 
451 /*
452  * This is called when the reader process gets the out-of-band (urgent)
453  * request to turn on the window-changing protocol.
454  */
455 void
456 writeroob(signo)
457 	int signo;
458 {
459 	struct sigaction sa;
460 
461 	if (dosigwinch == 0) {
462 		sendwindow();
463 		sigemptyset(&sa.sa_mask);
464 		sa.sa_handler = sigwinch;
465 		sa.sa_flags = SA_RESTART;
466 		(void)sigaction(SIGWINCH, &sa, (struct sigaction *) 0);
467 	}
468 	dosigwinch = 1;
469 }
470 
471 void
472 catch_child(signo)
473 	int signo;
474 {
475 	int status;
476 	pid_t pid;
477 
478 	for (;;) {
479 		pid = waitpid(-1, &status, WNOHANG|WUNTRACED);
480 		if (pid == 0)
481 			return;
482 		/* if the child (reader) dies, just quit */
483 		if (pid < 0 || (pid == child && !WIFSTOPPED(status)))
484 			done(WEXITSTATUS(status) | WTERMSIG(status));
485 	}
486 	/* NOTREACHED */
487 }
488 
489 /*
490  * writer: write to remote: 0 -> line.
491  * ~.				terminate
492  * ~^Z				suspend rlogin process.
493  * ~<delayed-suspend char>	suspend rlogin process, but leave reader alone.
494  */
495 void
496 writer()
497 {
498 	register int bol, local, n;
499 	char c;
500 
501 	bol = 1;			/* beginning of line */
502 	local = 0;
503 	for (;;) {
504 		n = read(STDIN_FILENO, &c, 1);
505 		if (n <= 0) {
506 			if (n < 0 && errno == EINTR)
507 				continue;
508 			break;
509 		}
510 		/*
511 		 * If we're at the beginning of the line and recognize a
512 		 * command character, then we echo locally.  Otherwise,
513 		 * characters are echo'd remotely.  If the command character
514 		 * is doubled, this acts as a force and local echo is
515 		 * suppressed.
516 		 */
517 		if (bol) {
518 			bol = 0;
519 			if (!noescape && c == escapechar) {
520 				local = 1;
521 				continue;
522 			}
523 		} else if (local) {
524 			local = 0;
525 			if (c == '.' || c == deftt.c_cc[VEOF]) {
526 				echo(c);
527 				break;
528 			}
529 			if (c == deftt.c_cc[VSUSP] || c == deftt.c_cc[VDSUSP]) {
530 				bol = 1;
531 				echo(c);
532 				stop(c);
533 				continue;
534 			}
535 			if (c != escapechar)
536 #ifdef CRYPT
537 #ifdef KERBEROS
538 				if (doencrypt)
539 					(void)des_write(rem,
540 					    (char *)&escapechar, 1);
541 				else
542 #endif
543 #endif
544 					(void)write(rem, &escapechar, 1);
545 		}
546 
547 #ifdef CRYPT
548 #ifdef KERBEROS
549 		if (doencrypt) {
550 			if (des_write(rem, &c, 1) == 0) {
551 				msg("line gone");
552 				break;
553 			}
554 		} else
555 #endif
556 #endif
557 			if (write(rem, &c, 1) == 0) {
558 				msg("line gone");
559 				break;
560 			}
561 		bol = c == deftt.c_cc[VKILL] || c == deftt.c_cc[VEOF] ||
562 		    c == deftt.c_cc[VINTR] || c == deftt.c_cc[VSUSP] ||
563 		    c == '\r' || c == '\n';
564 	}
565 }
566 
567 void
568 #if __STDC__
569 echo(register char c)
570 #else
571 echo(c)
572 	register char c;
573 #endif
574 {
575 	register char *p;
576 	char buf[8];
577 
578 	p = buf;
579 	c &= 0177;
580 	*p++ = escapechar;
581 	if (c < ' ') {
582 		*p++ = '^';
583 		*p++ = c + '@';
584 	} else if (c == 0177) {
585 		*p++ = '^';
586 		*p++ = '?';
587 	} else
588 		*p++ = c;
589 	*p++ = '\r';
590 	*p++ = '\n';
591 	(void)write(STDOUT_FILENO, buf, p - buf);
592 }
593 
594 void
595 #if __STDC__
596 stop(char cmdc)
597 #else
598 stop(cmdc)
599 	char cmdc;
600 #endif
601 {
602 	struct sigaction sa;
603 
604 	mode(0);
605 	sigemptyset(&sa.sa_mask);
606 	sa.sa_handler = SIG_IGN;
607 	sa.sa_flags = SA_RESTART;
608 	(void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0);
609 	(void)kill(cmdc == deftt.c_cc[VSUSP] ? 0 : getpid(), SIGTSTP);
610 	sa.sa_handler = catch_child;
611 	(void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0);
612 	mode(1);
613 	sigwinch(0);			/* check for size changes */
614 }
615 
616 void
617 sigwinch(signo)
618 	int signo;
619 {
620 	struct winsize ws;
621 
622 	if (dosigwinch && get_window_size(0, &ws) == 0 &&
623 	    memcmp(&ws, &winsize, sizeof(ws))) {
624 		winsize = ws;
625 		sendwindow();
626 	}
627 }
628 
629 /*
630  * Send the window size to the server via the magic escape
631  */
632 void
633 sendwindow()
634 {
635 	struct winsize *wp;
636 	char obuf[4 + sizeof (struct winsize)];
637 
638 	wp = (struct winsize *)(obuf+4);
639 	obuf[0] = 0377;
640 	obuf[1] = 0377;
641 	obuf[2] = 's';
642 	obuf[3] = 's';
643 	wp->ws_row = htons(winsize.ws_row);
644 	wp->ws_col = htons(winsize.ws_col);
645 	wp->ws_xpixel = htons(winsize.ws_xpixel);
646 	wp->ws_ypixel = htons(winsize.ws_ypixel);
647 
648 #ifdef CRYPT
649 #ifdef KERBEROS
650 	if(doencrypt)
651 		(void)des_write(rem, obuf, sizeof(obuf));
652 	else
653 #endif
654 #endif
655 		(void)write(rem, obuf, sizeof(obuf));
656 }
657 
658 /*
659  * reader: read from remote: line -> 1
660  */
661 #define	READING	1
662 #define	WRITING	2
663 
664 jmp_buf rcvtop;
665 pid_t ppid;
666 int rcvcnt, rcvstate;
667 char rcvbuf[8 * 1024];
668 
669 void
670 oob(signo)
671 	int signo;
672 {
673 	struct termios tt;
674 	int atmark, n, out, rcvd;
675 	char waste[BUFSIZ], mark;
676 
677 	out = O_RDWR;
678 	rcvd = 0;
679 	while (recv(rem, &mark, 1, MSG_OOB) < 0) {
680 		switch (errno) {
681 		case EWOULDBLOCK:
682 			/*
683 			 * Urgent data not here yet.  It may not be possible
684 			 * to send it yet if we are blocked for output and
685 			 * our input buffer is full.
686 			 */
687 			if (rcvcnt < sizeof(rcvbuf)) {
688 				n = read(rem, rcvbuf + rcvcnt,
689 				    sizeof(rcvbuf) - rcvcnt);
690 				if (n <= 0)
691 					return;
692 				rcvd += n;
693 			} else {
694 				n = read(rem, waste, sizeof(waste));
695 				if (n <= 0)
696 					return;
697 			}
698 			continue;
699 		default:
700 			return;
701 		}
702 	}
703 	if (mark & TIOCPKT_WINDOW) {
704 		/* Let server know about window size changes */
705 		(void)kill(ppid, SIGUSR1);
706 	}
707 	if (!eight && (mark & TIOCPKT_NOSTOP)) {
708 		tcgetattr(0, &tt);
709 		tt.c_iflag &= ~(IXON | IXOFF);
710 		tt.c_cc[VSTOP] = _POSIX_VDISABLE;
711 		tt.c_cc[VSTART] = _POSIX_VDISABLE;
712 		tcsetattr(0, TCSANOW, &tt);
713 	}
714 	if (!eight && (mark & TIOCPKT_DOSTOP)) {
715 		tcgetattr(0, &tt);
716 		tt.c_iflag |= (IXON|IXOFF);
717 		tt.c_cc[VSTOP] = deftt.c_cc[VSTOP];
718 		tt.c_cc[VSTART] = deftt.c_cc[VSTART];
719 		tcsetattr(0, TCSANOW, &tt);
720 	}
721 	if (mark & TIOCPKT_FLUSHWRITE) {
722 		(void)ioctl(1, TIOCFLUSH, (char *)&out);
723 		for (;;) {
724 			if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
725 				warn("ioctl SIOCATMARK (ignored)");
726 				break;
727 			}
728 			if (atmark)
729 				break;
730 			n = read(rem, waste, sizeof (waste));
731 			if (n <= 0)
732 				break;
733 		}
734 		/*
735 		 * Don't want any pending data to be output, so clear the recv
736 		 * buffer.  If we were hanging on a write when interrupted,
737 		 * don't want it to restart.  If we were reading, restart
738 		 * anyway.
739 		 */
740 		rcvcnt = 0;
741 		longjmp(rcvtop, 1);
742 	}
743 
744 	/* oob does not do FLUSHREAD (alas!) */
745 
746 	/*
747 	 * If we filled the receive buffer while a read was pending, longjmp
748 	 * to the top to restart appropriately.  Don't abort a pending write,
749 	 * however, or we won't know how much was written.
750 	 */
751 	if (rcvd && rcvstate == READING)
752 		longjmp(rcvtop, 1);
753 }
754 
755 /* reader: read from remote: line -> 1 */
756 int
757 reader(smask)
758 	sigset_t *smask;
759 {
760 	pid_t pid;
761 	int n, remaining;
762 	char *bufp;
763 	struct sigaction sa;
764 
765 #if BSD >= 43 || defined(SUNOS4)
766 	pid = getpid();		/* modern systems use positives for pid */
767 #else
768 	pid = -getpid();	/* old broken systems use negatives */
769 #endif
770 	sigemptyset(&sa.sa_mask);
771 	sa.sa_flags = SA_RESTART;
772 	sa.sa_handler = SIG_IGN;
773 	(void)sigaction(SIGTTOU, &sa, (struct sigaction *) 0);
774 	sa.sa_handler = oob;
775 	(void)sigaction(SIGURG, &sa, (struct sigaction *) 0);
776 	ppid = getppid();
777 	(void)fcntl(rem, F_SETOWN, pid);
778 	(void)setjmp(rcvtop);
779 	(void)sigprocmask(SIG_SETMASK, smask, (sigset_t *) 0);
780 	bufp = rcvbuf;
781 	for (;;) {
782 		while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) {
783 			rcvstate = WRITING;
784 			n = write(STDOUT_FILENO, bufp, remaining);
785 			if (n < 0) {
786 				if (errno != EINTR)
787 					return (-1);
788 				continue;
789 			}
790 			bufp += n;
791 		}
792 		bufp = rcvbuf;
793 		rcvcnt = 0;
794 		rcvstate = READING;
795 
796 #ifdef CRYPT
797 #ifdef KERBEROS
798 		if (doencrypt)
799 			rcvcnt = des_read(rem, rcvbuf, sizeof(rcvbuf));
800 		else
801 #endif
802 #endif
803 			rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf));
804 		if (rcvcnt == 0)
805 			return (0);
806 		if (rcvcnt < 0) {
807 			if (errno == EINTR)
808 				continue;
809 			warn("read");
810 			return (-1);
811 		}
812 	}
813 }
814 
815 void
816 mode(f)
817 	int f;
818 {
819 	struct termios tt;
820 
821 	switch (f) {
822 	case 0:
823 		tcsetattr(0, TCSADRAIN, &deftt);
824 		break;
825 	case 1:
826 		tt = deftt;
827 		tt.c_oflag &= ~(OPOST);
828 		tt.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
829 		tt.c_iflag &= ~(ICRNL);
830 		tt.c_cc[VMIN] = 1;
831 		tt.c_cc[VTIME] = 0;
832 		if (eight) {
833 			tt.c_iflag &= ~(IXON | IXOFF | ISTRIP);
834 			tt.c_cc[VSTOP] = _POSIX_VDISABLE;
835 			tt.c_cc[VSTART] = _POSIX_VDISABLE;
836 		}
837 		/*if (litout)
838 			lflags |= LLITOUT;*/
839 		tcsetattr(0, TCSADRAIN, &tt);
840 		break;
841 
842 	default:
843 		return;
844 	}
845 }
846 
847 void
848 lostpeer(signo)
849 	int signo;
850 {
851 	struct sigaction sa;
852 
853 	sigemptyset(&sa.sa_mask);
854 	sa.sa_flags = SA_RESTART;
855 	sa.sa_handler = SIG_IGN;
856 	(void)sigaction(SIGPIPE, &sa, (struct sigaction *) 0);
857 	msg("\007connection closed.");
858 	done(1);
859 }
860 
861 /* copy SIGURGs to the child process. */
862 void
863 copytochild(signo)
864 	int signo;
865 {
866 
867 	(void)kill(child, SIGURG);
868 }
869 
870 void
871 msg(str)
872 	char *str;
873 {
874 
875 	(void)fprintf(stderr, "rlogin: %s\r\n", str);
876 }
877 
878 #ifdef KERBEROS
879 /* VARARGS */
880 void
881 #if __STDC__
882 warning(const char *fmt, ...)
883 #else
884 warning(fmt, va_alist)
885 	char *fmt;
886 	va_dcl
887 #endif
888 {
889 	va_list ap;
890 
891 	(void)fprintf(stderr, "rlogin: warning, using standard rlogin: ");
892 #ifdef __STDC__
893 	va_start(ap, fmt);
894 #else
895 	va_start(ap);
896 #endif
897 	vfprintf(stderr, fmt, ap);
898 	va_end(ap);
899 	(void)fprintf(stderr, ".\n");
900 }
901 #endif
902 
903 __dead void
904 usage()
905 {
906 	(void)fprintf(stderr,
907 	    "usage: rlogin [ -%s]%s[-e char] [ -l username ] [username@]host\n",
908 #ifdef KERBEROS
909 #ifdef CRYPT
910 	    "8EKLx", " [-k realm] ");
911 #else
912 	    "8EKL", " [-k realm] ");
913 #endif
914 #else
915 	    "8EL", " ");
916 #endif
917 	exit(1);
918 }
919 
920 /*
921  * The following routine provides compatibility (such as it is) between older
922  * Suns and others.  Suns have only a `ttysize', so we convert it to a winsize.
923  */
924 #ifdef OLDSUN
925 int
926 get_window_size(fd, wp)
927 	int fd;
928 	struct winsize *wp;
929 {
930 	struct ttysize ts;
931 	int error;
932 
933 	if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0)
934 		return (error);
935 	wp->ws_row = ts.ts_lines;
936 	wp->ws_col = ts.ts_cols;
937 	wp->ws_xpixel = 0;
938 	wp->ws_ypixel = 0;
939 	return (0);
940 }
941 #endif
942 
943 u_int
944 getescape(p)
945 	register char *p;
946 {
947 	long val;
948 	int len;
949 
950 	if ((len = strlen(p)) == 1)	/* use any single char, including '\' */
951 		return ((u_int)*p);
952 					/* otherwise, \nnn */
953 	if (*p == '\\' && len >= 2 && len <= 4) {
954 		val = strtol(++p, NULL, 8);
955 		for (;;) {
956 			if (!*++p)
957 				return ((u_int)val);
958 			if (*p < '0' || *p > '8')
959 				break;
960 		}
961 	}
962 	msg("illegal option value -- e");
963 	usage();
964 	/* NOTREACHED */
965 }
966