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