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
main(argc,argv)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
speed(fd)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
speed(fd)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
doit(smask)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
setsignal(sig)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
done(status)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
writeroob(signo)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
catch_child(signo)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
writer()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__
echo(register char c)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__
stop(char cmdc)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
sigwinch(signo)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
sendwindow()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
oob(signo)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
reader(smask)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
mode(f)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
lostpeer(signo)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
copytochild(signo)863 copytochild(signo)
864 int signo;
865 {
866
867 (void)kill(child, SIGURG);
868 }
869
870 void
msg(str)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__
warning(const char * fmt,...)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
usage()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
get_window_size(fd,wp)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
getescape(p)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