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