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