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