xref: /original-bsd/usr.bin/rlogin/rlogin.c (revision bb2d502b)
1 /*
2  * Copyright (c) 1983 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #ifndef lint
19 char copyright[] =
20 "@(#) Copyright (c) 1983 The Regents of the University of California.\n\
21  All rights reserved.\n";
22 #endif /* not lint */
23 
24 #ifndef lint
25 static char sccsid[] = "@(#)rlogin.c	5.12 (Berkeley) 9/19/88";
26 #endif /* not lint */
27 
28 /*
29  * rlogin - remote login
30  */
31 #include <sys/param.h>
32 #include <sys/errno.h>
33 #include <sys/file.h>
34 #include <sys/socket.h>
35 #include <sys/time.h>
36 #include <sys/resource.h>
37 #include <sys/wait.h>
38 
39 #include <netinet/in.h>
40 
41 #include <stdio.h>
42 #include <sgtty.h>
43 #include <errno.h>
44 #include <pwd.h>
45 #include <signal.h>
46 #include <setjmp.h>
47 #include <netdb.h>
48 
49 #ifdef	KERBEROS
50 #include <kerberos/krb.h>
51 int		encrypt = 0;
52 char		krb_realm[REALM_SZ];
53 CREDENTIALS	cred;
54 Key_schedule	schedule;
55 int		use_kerberos = 1;
56 #endif	/* KERBEROS */
57 
58 # ifndef TIOCPKT_WINDOW
59 # define TIOCPKT_WINDOW 0x80
60 # endif TIOCPKT_WINDOW
61 
62 /* concession to sun */
63 # ifndef SIGUSR1
64 # define SIGUSR1 30
65 # endif SIGUSR1
66 
67 char	*index(), *rindex(), *malloc(), *getenv(), *strcat(), *strcpy();
68 struct	passwd *getpwuid();
69 char	*name;
70 int	rem;
71 char	cmdchar = '~';
72 int	eight;
73 int	litout;
74 char	*speeds[] =
75     { "0", "50", "75", "110", "134", "150", "200", "300",
76       "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" };
77 char	term[256] = "network";
78 extern	int errno;
79 int	lostpeer();
80 int	dosigwinch = 0;
81 #ifndef sigmask
82 #define sigmask(m)	(1 << ((m)-1))
83 #endif
84 #ifdef sun
85 struct winsize {
86 	unsigned short ws_row, ws_col;
87 	unsigned short ws_xpixel, ws_ypixel;
88 };
89 #endif sun
90 struct	winsize winsize;
91 int	sigwinch(), oob();
92 
93 /*
94  * The following routine provides compatibility (such as it is)
95  * between 4.2BSD Suns and others.  Suns have only a `ttysize',
96  * so we convert it to a winsize.
97  */
98 #ifdef sun
99 int
100 get_window_size(fd, wp)
101 	int fd;
102 	struct winsize *wp;
103 {
104 	struct ttysize ts;
105 	int error;
106 
107 	if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0)
108 		return (error);
109 	wp->ws_row = ts.ts_lines;
110 	wp->ws_col = ts.ts_cols;
111 	wp->ws_xpixel = 0;
112 	wp->ws_ypixel = 0;
113 	return (0);
114 }
115 #else sun
116 #define get_window_size(fd, wp)	ioctl(fd, TIOCGWINSZ, wp)
117 #endif sun
118 
119 main(argc, argv)
120 	int argc;
121 	char **argv;
122 {
123 	char *host, *cp;
124 	struct sgttyb ttyb;
125 	struct passwd *pwd;
126 	struct servent *sp;
127 	int uid, options = 0, oldmask;
128 	int on = 1;
129 
130 	host = rindex(argv[0], '/');
131 	if (host)
132 		host++;
133 	else
134 		host = argv[0];
135 	argv++, --argc;
136 	if (!strcmp(host, "rlogin"))
137 		host = *argv++, --argc;
138 another:
139 	if (argc > 0 && !strcmp(*argv, "-d")) {
140 		argv++, argc--;
141 		options |= SO_DEBUG;
142 		goto another;
143 	}
144 	if (argc > 0 && !strcmp(*argv, "-l")) {
145 		argv++, argc--;
146 		if (argc == 0)
147 			goto usage;
148 		name = *argv++; argc--;
149 		goto another;
150 	}
151 	if (argc > 0 && !strncmp(*argv, "-e", 2)) {
152 		cmdchar = argv[0][2];
153 		argv++, argc--;
154 		goto another;
155 	}
156 	if (argc > 0 && !strcmp(*argv, "-8")) {
157 		eight = 1;
158 		argv++, argc--;
159 		goto another;
160 	}
161 	if (argc > 0 && !strcmp(*argv, "-L")) {
162 		litout = 1;
163 		argv++, argc--;
164 		goto another;
165 	}
166 
167 #ifdef	KERBEROS
168 	if (argc > 0 && !strcmp(*argv, "-x")) {
169 		encrypt = 1;
170 		des_set_key(cred.session, schedule);
171 		argv++, argc--;
172 		goto another;
173 	}
174 	if (argc > 0 && !strcmp(*argv, "-k")) {
175 		argv++, argc--;
176 		if(argc <= 0 || (**argv == '-')) {
177 			fprintf(stderr, "-k option requires an argument\n");
178 			exit(1);
179 		}
180 		strncpy(krb_realm, *argv, REALM_SZ);
181 		argv++, argc--;
182 		goto another;
183 	}
184 
185 #endif	/* KERBEROS */
186 
187 	if (host == 0)
188 		goto usage;
189 	if (argc > 0)
190 		goto usage;
191 	pwd = getpwuid(getuid());
192 	if (pwd == 0) {
193 		fprintf(stderr, "Who are you?\n");
194 		exit(1);
195 	}
196 #ifdef	KERBEROS
197 	sp = getservbyname((encrypt ? "eklogin" : "klogin"), "tcp");
198 	if(sp == NULL) {
199 		use_kerberos = 0;
200 		old_warning("klogin service unknown");
201 		sp = getservbyname("login", "tcp");
202 	}
203 #else
204 	sp = getservbyname("login", "tcp");
205 #endif
206 	if (sp == 0) {
207 		fprintf(stderr, "rlogin: login/tcp: unknown service\n");
208 		exit(2);
209 	}
210 	cp = getenv("TERM");
211 	if (cp)
212 		(void) strcpy(term, cp);
213 	if (ioctl(0, TIOCGETP, &ttyb) == 0) {
214 		(void) strcat(term, "/");
215 		(void) strcat(term, speeds[ttyb.sg_ospeed]);
216 	}
217 	(void) get_window_size(0, &winsize);
218 	(void) signal(SIGPIPE, lostpeer);
219 	/* will use SIGUSR1 for window size hack, so hold it off */
220 	oldmask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1));
221 
222 #ifdef	KERBEROS
223 try_connect:
224 	if(use_kerberos) {
225 		rem = KSUCCESS;
226 		if(krb_realm[0] == '\0') {
227 			rem = krb_get_lrealm(krb_realm, 1);
228 		}
229 		if(rem == KSUCCESS) {
230 			setreuid(0,getuid());
231 			if(encrypt) {
232 				rem = krcmd_mutual(
233 					&host, sp->s_port,
234 					name ? name : pwd->pw_name, term,
235 					0, krb_realm,
236 					&cred, schedule
237 				);
238 			} else {
239 				rem = krcmd(
240 			    		&host, sp->s_port,
241 					name ? name : pwd->pw_name, term,
242 					0, krb_realm
243 				);
244 			}
245 			setuid(geteuid());
246 		} else {
247 			fprintf(
248 				stderr,
249 				"rlogin: Kerberos error getting local realm %s\n",
250 				krb_err_txt[rem]
251 			);
252 			exit(1);
253 		}
254 		if((rem < 0) && errno == ECONNREFUSED) {
255 			use_kerberos = 0;
256 			sp = getservbyname("login", "tcp");
257 			if(sp == NULL) {
258 				fprintf(stderr, "unknown service login/tcp\n");
259 				exit(1);
260 			}
261 			old_warning("remote host doesn't support Kerberos");
262 			goto try_connect;
263 		}
264 	} else {
265 		if(encrypt) {
266 			fprintf(stderr, "The -x flag requires Kerberos authencation\n");
267 			exit(1);
268 		}
269         	rem = rcmd(&host, sp->s_port, pwd->pw_name,
270 	    		name ? name : pwd->pw_name, term, 0);
271 	}
272 #else
273        	rem = rcmd(&host, sp->s_port, pwd->pw_name,
274     		name ? name : pwd->pw_name, term, 0);
275 #endif
276 
277 	if(rem < 0)
278 		exit(1);
279 
280 	if (options & SO_DEBUG &&
281 	    setsockopt(rem, SOL_SOCKET, SO_DEBUG, &on, sizeof (on)) < 0)
282 		perror("rlogin: setsockopt (SO_DEBUG)");
283 	uid = getuid();
284 	if (setuid(uid) < 0) {
285 		perror("rlogin: setuid");
286 		exit(1);
287 	}
288 	doit(oldmask);
289 	/*NOTREACHED*/
290 usage:
291 	fprintf(stderr,
292 #ifdef	KERBEROS
293 	    "usage: rlogin host [ -ex ] [ -l username ] [ -k realm ] [ -8 ] [ -L ] [ -x ]\n");
294 #else
295 	    "usage: rlogin host [ -ex ] [ -l username ] [ -8 ] [ -L ]\n");
296 #endif
297 	exit(1);
298 }
299 
300 #define CRLF "\r\n"
301 
302 int	child;
303 int	catchild();
304 int	copytochild(), writeroob();
305 
306 int	defflags, tabflag;
307 int	deflflags;
308 char	deferase, defkill;
309 struct	tchars deftc;
310 struct	ltchars defltc;
311 struct	tchars notc =	{ -1, -1, -1, -1, -1, -1 };
312 struct	ltchars noltc =	{ -1, -1, -1, -1, -1, -1 };
313 
314 doit(oldmask)
315 {
316 	int exit();
317 	struct sgttyb sb;
318 
319 	(void) ioctl(0, TIOCGETP, (char *)&sb);
320 	defflags = sb.sg_flags;
321 	tabflag = defflags & TBDELAY;
322 	defflags &= ECHO | CRMOD;
323 	deferase = sb.sg_erase;
324 	defkill = sb.sg_kill;
325 	(void) ioctl(0, TIOCLGET, (char *)&deflflags);
326 	(void) ioctl(0, TIOCGETC, (char *)&deftc);
327 	notc.t_startc = deftc.t_startc;
328 	notc.t_stopc = deftc.t_stopc;
329 	(void) ioctl(0, TIOCGLTC, (char *)&defltc);
330 	(void) signal(SIGINT, SIG_IGN);
331 	setsignal(SIGHUP, exit);
332 	setsignal(SIGQUIT, exit);
333 	child = fork();
334 	if (child == -1) {
335 		perror("rlogin: fork");
336 		done(1);
337 	}
338 	if (child == 0) {
339 		mode(1);
340 		if (reader(oldmask) == 0) {
341 			prf("Connection closed.");
342 			exit(0);
343 		}
344 		sleep(1);
345 		prf("\007Connection closed.");
346 		exit(3);
347 	}
348 
349 	/*
350 	 * We may still own the socket, and may have a pending SIGURG
351 	 * (or might receive one soon) that we really want to send to
352 	 * the reader.  Set a trap that simply copies such signals to
353 	 * the child.
354 	 */
355 	(void) signal(SIGURG, copytochild);
356 	(void) signal(SIGUSR1, writeroob);
357 	(void) sigsetmask(oldmask);
358 	(void) signal(SIGCHLD, catchild);
359 	writer();
360 	prf("Closed connection.");
361 	done(0);
362 }
363 
364 /*
365  * Trap a signal, unless it is being ignored.
366  */
367 setsignal(sig, act)
368 	int sig, (*act)();
369 {
370 	int omask = sigblock(sigmask(sig));
371 
372 	if (signal(sig, act) == SIG_IGN)
373 		(void) signal(sig, SIG_IGN);
374 	(void) sigsetmask(omask);
375 }
376 
377 done(status)
378 	int status;
379 {
380 	int w;
381 
382 	mode(0);
383 	if (child > 0) {
384 		/* make sure catchild does not snap it up */
385 		(void) signal(SIGCHLD, SIG_DFL);
386 		if (kill(child, SIGKILL) >= 0)
387 			while ((w = wait((union wait *)0)) > 0 && w != child)
388 				/*void*/;
389 	}
390 	exit(status);
391 }
392 
393 /*
394  * Copy SIGURGs to the child process.
395  */
396 copytochild()
397 {
398 
399 	(void) kill(child, SIGURG);
400 }
401 
402 /*
403  * This is called when the reader process gets the out-of-band (urgent)
404  * request to turn on the window-changing protocol.
405  */
406 writeroob()
407 {
408 
409 	if (dosigwinch == 0) {
410 		sendwindow();
411 		(void) signal(SIGWINCH, sigwinch);
412 	}
413 	dosigwinch = 1;
414 }
415 
416 catchild()
417 {
418 	union wait status;
419 	int pid;
420 
421 again:
422 	pid = wait3(&status, WNOHANG|WUNTRACED, (struct rusage *)0);
423 	if (pid == 0)
424 		return;
425 	/*
426 	 * if the child (reader) dies, just quit
427 	 */
428 	if (pid < 0 || pid == child && !WIFSTOPPED(status))
429 		done((int)(status.w_termsig | status.w_retcode));
430 	goto again;
431 }
432 
433 /*
434  * writer: write to remote: 0 -> line.
435  * ~.	terminate
436  * ~^Z	suspend rlogin process.
437  * ~^Y  suspend rlogin process, but leave reader alone.
438  */
439 writer()
440 {
441 	char c;
442 	register n;
443 	register bol = 1;               /* beginning of line */
444 	register local = 0;
445 
446 	for (;;) {
447 		n = read(0, &c, 1);
448 		if (n <= 0) {
449 			if (n < 0 && errno == EINTR)
450 				continue;
451 			break;
452 		}
453 		/*
454 		 * If we're at the beginning of the line
455 		 * and recognize a command character, then
456 		 * we echo locally.  Otherwise, characters
457 		 * are echo'd remotely.  If the command
458 		 * character is doubled, this acts as a
459 		 * force and local echo is suppressed.
460 		 */
461 		if (bol) {
462 			bol = 0;
463 			if (c == cmdchar) {
464 				bol = 0;
465 				local = 1;
466 				continue;
467 			}
468 		} else if (local) {
469 			local = 0;
470 			if (c == '.' || c == deftc.t_eofc) {
471 				echo(c);
472 				break;
473 			}
474 			if (c == defltc.t_suspc || c == defltc.t_dsuspc) {
475 				bol = 1;
476 				echo(c);
477 				stop(c);
478 				continue;
479 			}
480 			if (c != cmdchar) {
481 #ifdef	KERBEROS
482 				if(encrypt) {
483 					(void) des_write(
484 						rem,
485 						&cmdchar,
486 						1
487 					);
488 				} else
489 #endif
490 					(void) write(
491 						rem,
492 						&cmdchar,
493 						1
494 					);
495 			}
496 		}
497 
498 #ifdef	KERBEROS
499 		if(encrypt) {
500 			if (des_write(rem, &c, 1) == 0) {
501 				prf("line gone");
502 				break;
503 			}
504 		} else
505 #endif
506 			if (write(rem, &c, 1) == 0) {
507 				prf("line gone");
508 				break;
509 			}
510 		bol = c == defkill || c == deftc.t_eofc ||
511 		    c == deftc.t_intrc || c == defltc.t_suspc ||
512 		    c == '\r' || c == '\n';
513 	}
514 }
515 
516 echo(c)
517 register char c;
518 {
519 	char buf[8];
520 	register char *p = buf;
521 
522 	c &= 0177;
523 	*p++ = cmdchar;
524 	if (c < ' ') {
525 		*p++ = '^';
526 		*p++ = c + '@';
527 	} else if (c == 0177) {
528 		*p++ = '^';
529 		*p++ = '?';
530 	} else
531 		*p++ = c;
532 	*p++ = '\r';
533 	*p++ = '\n';
534 	(void) write(1, buf, p - buf);
535 }
536 
537 stop(cmdc)
538 	char cmdc;
539 {
540 	mode(0);
541 	(void) signal(SIGCHLD, SIG_IGN);
542 	(void) kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP);
543 	(void) signal(SIGCHLD, catchild);
544 	mode(1);
545 	sigwinch();			/* check for size changes */
546 }
547 
548 sigwinch()
549 {
550 	struct winsize ws;
551 
552 	if (dosigwinch && get_window_size(0, &ws) == 0 &&
553 	    bcmp(&ws, &winsize, sizeof (ws))) {
554 		winsize = ws;
555 		sendwindow();
556 	}
557 }
558 
559 /*
560  * Send the window size to the server via the magic escape
561  */
562 sendwindow()
563 {
564 	char obuf[4 + sizeof (struct winsize)];
565 	struct winsize *wp = (struct winsize *)(obuf+4);
566 
567 	obuf[0] = 0377;
568 	obuf[1] = 0377;
569 	obuf[2] = 's';
570 	obuf[3] = 's';
571 	wp->ws_row = htons(winsize.ws_row);
572 	wp->ws_col = htons(winsize.ws_col);
573 	wp->ws_xpixel = htons(winsize.ws_xpixel);
574 	wp->ws_ypixel = htons(winsize.ws_ypixel);
575 
576 #ifdef	KERBEROS
577 	if(encrypt)
578 		(void) des_write(rem, obuf, sizeof(obuf));
579 	else
580 #endif
581 		(void) write(rem, obuf, sizeof(obuf));
582 }
583 
584 /*
585  * reader: read from remote: line -> 1
586  */
587 #define	READING	1
588 #define	WRITING	2
589 
590 char	rcvbuf[8 * 1024];
591 int	rcvcnt;
592 int	rcvstate;
593 int	ppid;
594 jmp_buf	rcvtop;
595 
596 oob()
597 {
598 	int out = FWRITE, atmark, n;
599 	int rcvd = 0;
600 	char waste[BUFSIZ], mark;
601 	struct sgttyb sb;
602 
603 	while (recv(rem, &mark, 1, MSG_OOB) < 0)
604 		switch (errno) {
605 
606 		case EWOULDBLOCK:
607 			/*
608 			 * Urgent data not here yet.
609 			 * It may not be possible to send it yet
610 			 * if we are blocked for output
611 			 * and our input buffer is full.
612 			 */
613 			if (rcvcnt < sizeof(rcvbuf)) {
614 				n = read(rem, rcvbuf + rcvcnt,
615 					sizeof(rcvbuf) - rcvcnt);
616 				if (n <= 0)
617 					return;
618 				rcvd += n;
619 			} else {
620 				n = read(rem, waste, sizeof(waste));
621 				if (n <= 0)
622 					return;
623 			}
624 			continue;
625 
626 		default:
627 			return;
628 	}
629 	if (mark & TIOCPKT_WINDOW) {
630 		/*
631 		 * Let server know about window size changes
632 		 */
633 		(void) kill(ppid, SIGUSR1);
634 	}
635 	if (!eight && (mark & TIOCPKT_NOSTOP)) {
636 		(void) ioctl(0, TIOCGETP, (char *)&sb);
637 		sb.sg_flags &= ~CBREAK;
638 		sb.sg_flags |= RAW;
639 		(void) ioctl(0, TIOCSETN, (char *)&sb);
640 		notc.t_stopc = -1;
641 		notc.t_startc = -1;
642 		(void) ioctl(0, TIOCSETC, (char *)&notc);
643 	}
644 	if (!eight && (mark & TIOCPKT_DOSTOP)) {
645 		(void) ioctl(0, TIOCGETP, (char *)&sb);
646 		sb.sg_flags &= ~RAW;
647 		sb.sg_flags |= CBREAK;
648 		(void) ioctl(0, TIOCSETN, (char *)&sb);
649 		notc.t_stopc = deftc.t_stopc;
650 		notc.t_startc = deftc.t_startc;
651 		(void) ioctl(0, TIOCSETC, (char *)&notc);
652 	}
653 	if (mark & TIOCPKT_FLUSHWRITE) {
654 		(void) ioctl(1, TIOCFLUSH, (char *)&out);
655 		for (;;) {
656 			if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
657 				perror("ioctl");
658 				break;
659 			}
660 			if (atmark)
661 				break;
662 			n = read(rem, waste, sizeof (waste));
663 			if (n <= 0)
664 				break;
665 		}
666 		/*
667 		 * Don't want any pending data to be output,
668 		 * so clear the recv buffer.
669 		 * If we were hanging on a write when interrupted,
670 		 * don't want it to restart.  If we were reading,
671 		 * restart anyway.
672 		 */
673 		rcvcnt = 0;
674 		longjmp(rcvtop, 1);
675 	}
676 
677 	/*
678 	 * oob does not do FLUSHREAD (alas!)
679 	 */
680 
681 	/*
682 	 * If we filled the receive buffer while a read was pending,
683 	 * longjmp to the top to restart appropriately.  Don't abort
684 	 * a pending write, however, or we won't know how much was written.
685 	 */
686 	if (rcvd && rcvstate == READING)
687 		longjmp(rcvtop, 1);
688 }
689 
690 /*
691  * reader: read from remote: line -> 1
692  */
693 reader(oldmask)
694 	int oldmask;
695 {
696 #if !defined(BSD) || BSD < 43
697 	int pid = -getpid();
698 #else
699 	int pid = getpid();
700 #endif
701 	int n, remaining;
702 	char *bufp = rcvbuf;
703 
704 	(void) signal(SIGTTOU, SIG_IGN);
705 	(void) signal(SIGURG, oob);
706 	ppid = getppid();
707 	(void) fcntl(rem, F_SETOWN, pid);
708 	(void) setjmp(rcvtop);
709 	(void) sigsetmask(oldmask);
710 	for (;;) {
711 		while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) {
712 			rcvstate = WRITING;
713 			n = write(1, bufp, remaining);
714 			if (n < 0) {
715 				if (errno != EINTR)
716 					return (-1);
717 				continue;
718 			}
719 			bufp += n;
720 		}
721 		bufp = rcvbuf;
722 		rcvcnt = 0;
723 		rcvstate = READING;
724 
725 #ifdef	KERBEROS
726 		if(encrypt)
727 			rcvcnt = des_read(rem, rcvbuf, sizeof(rcvbuf));
728 		else
729 #endif
730 			rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf));
731 		if (rcvcnt == 0)
732 			return (0);
733 		if (rcvcnt < 0) {
734 			if (errno == EINTR)
735 				continue;
736 			perror("read");
737 			return (-1);
738 		}
739 	}
740 }
741 
742 mode(f)
743 {
744 	struct tchars *tc;
745 	struct ltchars *ltc;
746 	struct sgttyb sb;
747 	int	lflags;
748 
749 	(void) ioctl(0, TIOCGETP, (char *)&sb);
750 	(void) ioctl(0, TIOCLGET, (char *)&lflags);
751 	switch (f) {
752 
753 	case 0:
754 		sb.sg_flags &= ~(CBREAK|RAW|TBDELAY);
755 		sb.sg_flags |= defflags|tabflag;
756 		tc = &deftc;
757 		ltc = &defltc;
758 		sb.sg_kill = defkill;
759 		sb.sg_erase = deferase;
760 		lflags = deflflags;
761 		break;
762 
763 	case 1:
764 		sb.sg_flags |= (eight ? RAW : CBREAK);
765 		sb.sg_flags &= ~defflags;
766 		/* preserve tab delays, but turn off XTABS */
767 		if ((sb.sg_flags & TBDELAY) == XTABS)
768 			sb.sg_flags &= ~TBDELAY;
769 		tc = &notc;
770 		ltc = &noltc;
771 		sb.sg_kill = sb.sg_erase = -1;
772 		if (litout)
773 			lflags |= LLITOUT;
774 		break;
775 
776 	default:
777 		return;
778 	}
779 	(void) ioctl(0, TIOCSLTC, (char *)ltc);
780 	(void) ioctl(0, TIOCSETC, (char *)tc);
781 	(void) ioctl(0, TIOCSETN, (char *)&sb);
782 	(void) ioctl(0, TIOCLSET, (char *)&lflags);
783 }
784 
785 /*VARARGS*/
786 prf(f, a1, a2, a3, a4, a5)
787 	char *f;
788 {
789 
790 	fprintf(stderr, f, a1, a2, a3, a4, a5);
791 	fprintf(stderr, CRLF);
792 }
793 
794 lostpeer()
795 {
796 
797 	(void) signal(SIGPIPE, SIG_IGN);
798 	prf("\007Connection closed.");
799 	done(1);
800 }
801 
802 old_warning(str)
803 	char	*str;
804 {
805 	prf("Warning: %s, using standard rlogin", str);
806 }
807