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