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