rlogin.c revision 93057
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 "$FreeBSD: head/usr.bin/rlogin/rlogin.c 93057 2002-03-23 23:35:42Z imp $"; 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 <openssl/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; 98int family = PF_UNSPEC; 99 100int noescape; 101u_char escapechar = '~'; 102 103char *speeds[] = { 104 "0", "50", "75", "110", "134", "150", "200", "300", "600", "1200", 105 "1800", "2400", "4800", "9600", "19200", "38400", "57600", "115200" 106#define MAX_SPEED_LENGTH (sizeof("115200") - 1) 107}; 108 109#define get_window_size(fd, wp) ioctl(fd, TIOCGWINSZ, wp) 110struct winsize winsize; 111 112void catch_child(int); 113void copytochild(int); 114void doit(long) __dead2; 115void done(int) __dead2; 116void echo(char); 117u_int getescape(char *); 118void lostpeer(int); 119void mode(int); 120void msg(char *); 121void oob(int); 122int reader(int); 123void sendwindow(void); 124void setsignal(int); 125void sigwinch(int); 126void stop(char); 127void usage(void) __dead2; 128void writer(void); 129void writeroob(int); 130 131int 132main(int argc, char *argv[]) 133{ 134 struct passwd *pw; 135 struct servent *sp; 136 struct sgttyb ttyb; 137 long omask; 138 int argoff, ch, dflag, Dflag, one, uid; 139 char *host, *localname, *p, *user, term[1024]; 140#ifdef KERBEROS 141 char *k; 142#endif 143 struct sockaddr_storage ss; 144 int sslen; 145 146 argoff = dflag = Dflag = 0; 147 one = 1; 148 host = localname = user = NULL; 149 150 if ((p = rindex(argv[0], '/'))) 151 ++p; 152 else 153 p = argv[0]; 154 155 if (strcmp(p, "rlogin")) 156 host = p; 157 158 /* handle "rlogin host flags" */ 159 if (!host && argc > 2 && argv[1][0] != '-') { 160 host = argv[1]; 161 argoff = 1; 162 } 163 164#ifdef KERBEROS 165#define OPTIONS "468DEKLde:i:k:l:x" 166#else 167#define OPTIONS "468DEKLde:i:l:" 168#endif 169 while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != -1) 170 switch(ch) { 171 case '4': 172 family = PF_INET; 173 break; 174 175 case '6': 176 family = PF_INET6; 177 break; 178 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 case 'i': 204 if (getuid() != 0) 205 errx(1, "-i user: permission denied"); 206 localname = optarg; 207 break; 208#ifdef KERBEROS 209 case 'k': 210 dest_realm = dst_realm_buf; 211 (void)strncpy(dest_realm, optarg, REALM_SZ); 212 break; 213#endif 214 case 'l': 215 user = optarg; 216 break; 217#ifdef CRYPT 218#ifdef KERBEROS 219 case 'x': 220 doencrypt = 1; 221 break; 222#endif 223#endif 224 case '?': 225 default: 226 usage(); 227 } 228 optind += argoff; 229 230 /* if haven't gotten a host yet, do so */ 231 if (!host && !(host = argv[optind++])) 232 usage(); 233 234 if (argv[optind]) 235 usage(); 236 237 if (!(pw = getpwuid(uid = getuid()))) 238 errx(1, "unknown user id"); 239 if (!user) 240 user = pw->pw_name; 241 if (!localname) 242 localname = pw->pw_name; 243 244 sp = NULL; 245#ifdef KERBEROS 246 k = auth_getval("auth_list"); 247 if (k && !strstr(k, "kerberos")) 248 use_kerberos = 0; 249 if (use_kerberos) { 250 sp = getservbyname((doencrypt ? "eklogin" : "klogin"), "tcp"); 251 if (sp == NULL) { 252 use_kerberos = 0; 253 warn("can't get entry for %s/tcp service", 254 doencrypt ? "eklogin" : "klogin"); 255 } 256 } 257#endif 258 if (sp == NULL) 259 sp = getservbyname("login", "tcp"); 260 if (sp == NULL) 261 errx(1, "login/tcp: unknown service"); 262 263#define MAX_TERM_LENGTH (sizeof(term) - 1 - MAX_SPEED_LENGTH - 1) 264 265 (void)strncpy(term, (p = getenv("TERM")) ? p : "network", 266 MAX_TERM_LENGTH); 267 term[MAX_TERM_LENGTH] = '\0'; 268 if (ioctl(0, TIOCGETP, &ttyb) == 0) { 269 (void)strcat(term, "/"); 270 (void)strcat(term, speeds[(int)ttyb.sg_ospeed]); 271 } 272 273 (void)get_window_size(0, &winsize); 274 275 (void)signal(SIGPIPE, lostpeer); 276 /* will use SIGUSR1 for window size hack, so hold it off */ 277 omask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1)); 278 /* 279 * We set SIGURG and SIGUSR1 below so that an 280 * incoming signal will be held pending rather than being 281 * discarded. Note that these routines will be ready to get 282 * a signal by the time that they are unblocked below. 283 */ 284 (void)signal(SIGURG, copytochild); 285 (void)signal(SIGUSR1, writeroob); 286 287#ifdef KERBEROS 288 if (use_kerberos) { 289 setuid(getuid()); 290 rem = KSUCCESS; 291 errno = 0; 292 if (dest_realm == NULL) 293 dest_realm = krb_realmofhost(host); 294 295#ifdef CRYPT 296 if (doencrypt) { 297 rem = krcmd_mutual(&host, sp->s_port, user, term, 0, 298 dest_realm, &cred, schedule); 299 des_set_key(&cred.session, schedule); 300 } else 301#endif /* CRYPT */ 302 rem = krcmd(&host, sp->s_port, user, term, 0, 303 dest_realm); 304 if (rem < 0) { 305 int i; 306 char **newargv; 307 308 sp = getservbyname("login", "tcp"); 309 if (sp == NULL) 310 errx(1, "unknown service login/tcp"); 311 if (errno == ECONNREFUSED) 312 warn("remote host doesn't support Kerberos"); 313 if (errno == ENOENT) 314 warn("can't provide Kerberos auth data"); 315 newargv = malloc((argc + 2) * sizeof(*newargv)); 316 if (newargv == NULL) 317 err(1, "malloc"); 318 newargv[0] = argv[0]; 319 newargv[1] = "-K"; 320 for(i = 1; i < argc; ++i) 321 newargv[i + 1] = argv[i]; 322 newargv[argc + 1] = NULL; 323 execv(_PATH_RLOGIN, newargv); 324 } 325 } else { 326#ifdef CRYPT 327 if (doencrypt) 328 errx(1, "the -x flag requires Kerberos authentication"); 329#endif /* CRYPT */ 330 rem = rcmd_af(&host, sp->s_port, localname, user, term, 0, 331 family); 332 } 333#else 334 rem = rcmd_af(&host, sp->s_port, localname, user, term, 0, family); 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 warn("setsockopt"); 343 if (Dflag && 344 setsockopt(rem, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)) < 0) 345 warn("setsockopt NODELAY (ignored)"); 346 347 sslen = sizeof(ss); 348 one = IPTOS_LOWDELAY; 349 if (getsockname(rem, (struct sockaddr *)&ss, &sslen) == 0 && 350 ss.ss_family == AF_INET) { 351 if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, 352 sizeof(int)) < 0) 353 warn("setsockopt TOS (ignored)"); 354 } else 355 if (ss.ss_family == AF_INET) 356 warn("setsockopt getsockname failed"); 357 358 (void)setuid(uid); 359 doit(omask); 360 /*NOTREACHED*/ 361} 362 363int child, defflags, deflflags, tabflag; 364char deferase, defkill; 365struct tchars deftc; 366struct ltchars defltc; 367struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 368struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 369 370void 371doit(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(int sig) 422{ 423 int omask = sigblock(sigmask(sig)); 424 425 if (signal(sig, exit) == SIG_IGN) 426 (void)signal(sig, SIG_IGN); 427 (void)sigsetmask(omask); 428} 429 430void 431done(int status) 432{ 433 int w, wstatus; 434 435 mode(0); 436 if (child > 0) { 437 /* make sure catch_child does not snap it up */ 438 (void)signal(SIGCHLD, SIG_DFL); 439 if (kill(child, SIGKILL) >= 0) 440 while ((w = wait(&wstatus)) > 0 && w != child); 441 } 442 exit(status); 443} 444 445int dosigwinch; 446 447/* 448 * This is called when the reader process gets the out-of-band (urgent) 449 * request to turn on the window-changing protocol. 450 */ 451void 452writeroob(int signo) 453{ 454 if (dosigwinch == 0) { 455 sendwindow(); 456 (void)signal(SIGWINCH, sigwinch); 457 } 458 dosigwinch = 1; 459} 460 461void 462catch_child(int signo) 463{ 464 union wait status; 465 int pid; 466 467 for (;;) { 468 pid = wait3((int *)&status, WNOHANG|WUNTRACED, NULL); 469 if (pid == 0) 470 return; 471 /* if the child (reader) dies, just quit */ 472 if (pid < 0 || (pid == child && !WIFSTOPPED(status))) 473 done((int)(status.w_termsig | status.w_retcode)); 474 } 475 /* NOTREACHED */ 476} 477 478/* 479 * writer: write to remote: 0 -> line. 480 * ~. terminate 481 * ~^Z suspend rlogin process. 482 * ~<delayed-suspend char> suspend rlogin process, but leave reader alone. 483 */ 484void 485writer(void) 486{ 487 int bol, local, n; 488 char c; 489 490 bol = 1; /* beginning of line */ 491 local = 0; 492 for (;;) { 493 n = read(STDIN_FILENO, &c, 1); 494 if (n <= 0) { 495 if (n < 0 && errno == EINTR) 496 continue; 497 break; 498 } 499 /* 500 * If we're at the beginning of the line and recognize a 501 * command character, then we echo locally. Otherwise, 502 * characters are echo'd remotely. If the command character 503 * is doubled, this acts as a force and local echo is 504 * suppressed. 505 */ 506 if (bol) { 507 bol = 0; 508 if (!noescape && c == escapechar) { 509 local = 1; 510 continue; 511 } 512 } else if (local) { 513 local = 0; 514 if (c == '.' || c == deftc.t_eofc) { 515 echo(c); 516 break; 517 } 518 if (c == defltc.t_suspc || c == defltc.t_dsuspc) { 519 bol = 1; 520 echo(c); 521 stop(c); 522 continue; 523 } 524 if (c != escapechar) 525#ifdef CRYPT 526#ifdef KERBEROS 527 if (doencrypt) 528 (void)des_enc_write(rem, 529 (char *)&escapechar, 1, 530 schedule, &cred.session); 531 else 532#endif 533#endif 534 (void)write(rem, &escapechar, 1); 535 } 536 537#ifdef CRYPT 538#ifdef KERBEROS 539 if (doencrypt) { 540 if (des_enc_write(rem, &c, 1, schedule, &cred.session) == 0) { 541 msg("line gone"); 542 break; 543 } 544 } else 545#endif 546#endif 547 if (write(rem, &c, 1) == 0) { 548 msg("line gone"); 549 break; 550 } 551 bol = c == defkill || c == deftc.t_eofc || 552 c == deftc.t_intrc || c == defltc.t_suspc || 553 c == '\r' || c == '\n'; 554 } 555} 556 557void 558echo(char c) 559{ 560 char *p; 561 char buf[8]; 562 563 p = buf; 564 c &= 0177; 565 *p++ = escapechar; 566 if (c < ' ') { 567 *p++ = '^'; 568 *p++ = c + '@'; 569 } else if (c == 0177) { 570 *p++ = '^'; 571 *p++ = '?'; 572 } else 573 *p++ = c; 574 *p++ = '\r'; 575 *p++ = '\n'; 576 (void)write(STDOUT_FILENO, buf, p - buf); 577} 578 579void 580stop(char cmdc) 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(void) 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_enc_write(rem, obuf, sizeof(obuf), 626 schedule, &cred.session); 627 else 628#endif 629#endif 630 (void)write(rem, obuf, sizeof(obuf)); 631} 632 633/* 634 * reader: read from remote: line -> 1 635 */ 636#define READING 1 637#define WRITING 2 638 639jmp_buf rcvtop; 640int ppid, rcvcnt, rcvstate; 641char rcvbuf[8 * 1024]; 642 643void 644oob(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 warn("ioctl"); 703 break; 704 } 705 if (atmark) 706 break; 707 n = read(rem, waste, sizeof (waste)); 708 if (n <= 0) 709 break; 710 } 711 /* 712 * Don't want any pending data to be output, so clear the recv 713 * buffer. If we were hanging on a write when interrupted, 714 * don't want it to restart. If we were reading, restart 715 * anyway. 716 */ 717 rcvcnt = 0; 718 longjmp(rcvtop, 1); 719 } 720 721 /* oob does not do FLUSHREAD (alas!) */ 722 723 /* 724 * If we filled the receive buffer while a read was pending, longjmp 725 * to the top to restart appropriately. Don't abort a pending write, 726 * however, or we won't know how much was written. 727 */ 728 if (rcvd && rcvstate == READING) 729 longjmp(rcvtop, 1); 730} 731 732/* reader: read from remote: line -> 1 */ 733int 734reader(int omask) 735{ 736 int pid, n, remaining; 737 char *bufp; 738 739#if BSD >= 43 || defined(SUNOS4) 740 pid = getpid(); /* modern systems use positives for pid */ 741#else 742 pid = -getpid(); /* old broken systems use negatives */ 743#endif 744 (void)signal(SIGTTOU, SIG_IGN); 745 (void)signal(SIGURG, oob); 746 (void)signal(SIGUSR1, oob); /* When propogating SIGURG from parent */ 747 ppid = getppid(); 748 (void)fcntl(rem, F_SETOWN, pid); 749 (void)setjmp(rcvtop); 750 (void)sigsetmask(omask); 751 bufp = rcvbuf; 752 for (;;) { 753 while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) { 754 rcvstate = WRITING; 755 n = write(STDOUT_FILENO, bufp, remaining); 756 if (n < 0) { 757 if (errno != EINTR) 758 return (-1); 759 continue; 760 } 761 bufp += n; 762 } 763 bufp = rcvbuf; 764 rcvcnt = 0; 765 rcvstate = READING; 766 767#ifdef CRYPT 768#ifdef KERBEROS 769 if (doencrypt) 770 rcvcnt = des_enc_read(rem, rcvbuf, sizeof(rcvbuf), 771 schedule, &cred.session); 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 warn("read"); 782 return (-1); 783 } 784 } 785} 786 787void 788mode(int f) 789{ 790 struct ltchars *ltc; 791 struct sgttyb sb; 792 struct tchars *tc; 793 int lflags; 794 795 (void)ioctl(0, TIOCGETP, (char *)&sb); 796 (void)ioctl(0, TIOCLGET, (char *)&lflags); 797 switch(f) { 798 case 0: 799 sb.sg_flags &= ~(CBREAK|RAW|TBDELAY); 800 sb.sg_flags |= defflags|tabflag; 801 tc = &deftc; 802 ltc = &defltc; 803 sb.sg_kill = defkill; 804 sb.sg_erase = deferase; 805 lflags = deflflags; 806 break; 807 case 1: 808 sb.sg_flags |= (eight ? RAW : CBREAK); 809 sb.sg_flags &= ~defflags; 810 /* preserve tab delays, but turn off XTABS */ 811 if ((sb.sg_flags & TBDELAY) == XTABS) 812 sb.sg_flags &= ~TBDELAY; 813 tc = ¬c; 814 ltc = &noltc; 815 sb.sg_kill = sb.sg_erase = -1; 816 if (litout) 817 lflags |= LLITOUT; 818 break; 819 default: 820 return; 821 } 822 (void)ioctl(0, TIOCSLTC, (char *)ltc); 823 (void)ioctl(0, TIOCSETC, (char *)tc); 824 (void)ioctl(0, TIOCSETN, (char *)&sb); 825 (void)ioctl(0, TIOCLSET, (char *)&lflags); 826} 827 828void 829lostpeer(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 via SIGUSR1. */ 837void 838copytochild(int signo) 839{ 840 (void)kill(child, SIGUSR1); 841} 842 843void 844msg(char *str) 845{ 846 (void)fprintf(stderr, "rlogin: %s\r\n", str); 847} 848 849void 850usage(void) 851{ 852 (void)fprintf(stderr, 853 "usage: rlogin [-46%s]%s[-e char] [-i localname] [-l username] host\n", 854#ifdef KERBEROS 855#ifdef CRYPT 856 "8DEKLdx", " [-k realm] "); 857#else 858 "8DEKLd", " [-k realm] "); 859#endif 860#else 861 "8DEKLd", " "); 862#endif 863 exit(1); 864} 865 866u_int 867getescape(char *p) 868{ 869 long val; 870 int len; 871 872 if ((len = strlen(p)) == 1) /* use any single char, including '\' */ 873 return ((u_int)*p); 874 /* otherwise, \nnn */ 875 if (*p == '\\' && len >= 2 && len <= 4) { 876 val = strtol(++p, NULL, 8); 877 for (;;) { 878 if (!*++p) 879 return ((u_int)val); 880 if (*p < '0' || *p > '8') 881 break; 882 } 883 } 884 msg("illegal option value -- e"); 885 usage(); 886 /* NOTREACHED */ 887} 888