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