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