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