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