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