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