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