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