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