rlogin.c revision 96196
1/* 2 * Copyright (c) 1983, 1990, 1993 3 * The Regents of the University of California. All rights reserved. 4 * Copyright (c) 2002 Networks Associates Technology, Inc. 5 * All rights reserved. 6 * 7 * Portions of this software were developed for the FreeBSD Project by 8 * ThinkSec AS and NAI Labs, the Security Research Division of Network 9 * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 10 * ("CBOSS"), as part of the DARPA CHATS research program. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the University of 23 * California, Berkeley and its contributors. 24 * 4. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 */ 40 41#ifndef lint 42static const char copyright[] = 43"@(#) Copyright (c) 1983, 1990, 1993\n\ 44 The Regents of the University of California. All rights reserved.\n"; 45#endif /* not lint */ 46 47#ifndef lint 48static const char sccsid[] = "@(#)rlogin.c 8.1 (Berkeley) 6/6/93"; 49#endif /* not lint */ 50 51/* 52 * rlogin - remote login 53 */ 54#include <sys/cdefs.h> 55__FBSDID("$FreeBSD: head/usr.bin/rlogin/rlogin.c 96196 2002-05-08 00:47:01Z des $"); 56 57#include <sys/param.h> 58#include <sys/socket.h> 59#include <sys/time.h> 60#include <sys/resource.h> 61#include <sys/wait.h> 62 63#include <netinet/in.h> 64#include <netinet/in_systm.h> 65#include <netinet/ip.h> 66#include <netinet/tcp.h> 67 68#include <err.h> 69#include <errno.h> 70#include <fcntl.h> 71#include <libutil.h> 72#include <netdb.h> 73#include <pwd.h> 74#include <setjmp.h> 75#include <sgtty.h> 76#include <signal.h> 77#include <stdio.h> 78#include <stdlib.h> 79#include <string.h> 80#include <unistd.h> 81 82#ifdef KERBEROS 83#include <openssl/des.h> 84#include <krb.h> 85 86#include "krb.h" 87 88CREDENTIALS cred; 89Key_schedule schedule; 90int use_kerberos = 1, doencrypt; 91char dst_realm_buf[REALM_SZ], *dest_realm = NULL; 92#endif 93 94#ifndef TIOCPKT_WINDOW 95#define TIOCPKT_WINDOW 0x80 96#endif 97 98/* concession to Sun */ 99#ifndef SIGUSR1 100#define SIGUSR1 30 101#endif 102 103int eight, litout, rem; 104int family = PF_UNSPEC; 105 106int noescape; 107u_char escapechar = '~'; 108 109const char *speeds[] = { 110 "0", "50", "75", "110", "134", "150", "200", "300", "600", "1200", 111 "1800", "2400", "4800", "9600", "19200", "38400", "57600", "115200" 112#define MAX_SPEED_LENGTH (sizeof("115200") - 1) 113}; 114 115#define get_window_size(fd, wp) ioctl(fd, TIOCGWINSZ, wp) 116struct winsize winsize; 117 118void catch_child(int); 119void copytochild(int); 120void doit(long) __dead2; 121void done(int) __dead2; 122void echo(char); 123u_int getescape(char *); 124void lostpeer(int); 125void mode(int); 126void msg(const char *); 127void oob(int); 128int reader(int); 129void sendwindow(void); 130void setsignal(int); 131void sigwinch(int); 132void stop(char); 133void usage(void) __dead2; 134void writer(void); 135void writeroob(int); 136 137int 138main(int argc, char *argv[]) 139{ 140 struct passwd *pw; 141 struct servent *sp; 142 struct sgttyb ttyb; 143 long omask; 144 int argoff, ch, dflag, Dflag, one, uid; 145 char *host, *localname, *p, *user, term[1024]; 146#ifdef KERBEROS 147 char *k; 148#endif 149 struct sockaddr_storage ss; 150 int sslen; 151 152 argoff = dflag = Dflag = 0; 153 one = 1; 154 host = localname = user = NULL; 155 156 if ((p = rindex(argv[0], '/'))) 157 ++p; 158 else 159 p = argv[0]; 160 161 if (strcmp(p, "rlogin")) 162 host = p; 163 164 /* handle "rlogin host flags" */ 165 if (!host && argc > 2 && argv[1][0] != '-') { 166 host = argv[1]; 167 argoff = 1; 168 } 169 170#ifdef KERBEROS 171#define OPTIONS "468DEKLde:i:k:l:x" 172#else 173#define OPTIONS "468DEKLde:i:l:" 174#endif 175 while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != -1) 176 switch(ch) { 177 case '4': 178 family = PF_INET; 179 break; 180 181 case '6': 182 family = PF_INET6; 183 break; 184 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 family); 338 } 339#else 340 rem = rcmd_af(&host, sp->s_port, localname, user, term, 0, family); 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(long omask) 378{ 379 struct sgttyb sb; 380 381 (void)ioctl(0, TIOCGETP, (char *)&sb); 382 defflags = sb.sg_flags; 383 tabflag = defflags & TBDELAY; 384 defflags &= ECHO | CRMOD; 385 deferase = sb.sg_erase; 386 defkill = sb.sg_kill; 387 (void)ioctl(0, TIOCLGET, &deflflags); 388 (void)ioctl(0, TIOCGETC, &deftc); 389 notc.t_startc = deftc.t_startc; 390 notc.t_stopc = deftc.t_stopc; 391 (void)ioctl(0, TIOCGLTC, &defltc); 392 (void)signal(SIGINT, SIG_IGN); 393 setsignal(SIGHUP); 394 setsignal(SIGQUIT); 395 child = fork(); 396 if (child == -1) { 397 warn("fork"); 398 done(1); 399 } 400 if (child == 0) { 401 mode(1); 402 if (reader(omask) == 0) { 403 msg("connection closed."); 404 exit(0); 405 } 406 sleep(1); 407 msg("\007connection closed."); 408 exit(1); 409 } 410 411 /* 412 * We may still own the socket, and may have a pending SIGURG (or might 413 * receive one soon) that we really want to send to the reader. When 414 * one of these comes in, the trap copytochild simply copies such 415 * signals to the child. We can now unblock SIGURG and SIGUSR1 416 * that were set above. 417 */ 418 (void)sigsetmask(omask); 419 (void)signal(SIGCHLD, catch_child); 420 writer(); 421 msg("closed connection."); 422 done(0); 423} 424 425/* trap a signal, unless it is being ignored. */ 426void 427setsignal(int sig) 428{ 429 int omask = sigblock(sigmask(sig)); 430 431 if (signal(sig, exit) == SIG_IGN) 432 (void)signal(sig, SIG_IGN); 433 (void)sigsetmask(omask); 434} 435 436void 437done(int status) 438{ 439 int w, wstatus; 440 441 mode(0); 442 if (child > 0) { 443 /* make sure catch_child does not snap it up */ 444 (void)signal(SIGCHLD, SIG_DFL); 445 if (kill(child, SIGKILL) >= 0) 446 while ((w = wait(&wstatus)) > 0 && w != child); 447 } 448 exit(status); 449} 450 451int dosigwinch; 452 453/* 454 * This is called when the reader process gets the out-of-band (urgent) 455 * request to turn on the window-changing protocol. 456 */ 457void 458writeroob(int signo __unused) 459{ 460 if (dosigwinch == 0) { 461 sendwindow(); 462 (void)signal(SIGWINCH, sigwinch); 463 } 464 dosigwinch = 1; 465} 466 467void 468catch_child(int signo __unused) 469{ 470 union wait status; 471 int pid; 472 473 for (;;) { 474 pid = wait3((int *)&status, WNOHANG|WUNTRACED, NULL); 475 if (pid == 0) 476 return; 477 /* if the child (reader) dies, just quit */ 478 if (pid < 0 || (pid == child && !WIFSTOPPED(status))) 479 done((int)(status.w_termsig | status.w_retcode)); 480 } 481 /* NOTREACHED */ 482} 483 484/* 485 * writer: write to remote: 0 -> line. 486 * ~. terminate 487 * ~^Z suspend rlogin process. 488 * ~<delayed-suspend char> suspend rlogin process, but leave reader alone. 489 */ 490void 491writer(void) 492{ 493 int bol, local, n; 494 char c; 495 496 bol = 1; /* beginning of line */ 497 local = 0; 498 for (;;) { 499 n = read(STDIN_FILENO, &c, 1); 500 if (n <= 0) { 501 if (n < 0 && errno == EINTR) 502 continue; 503 break; 504 } 505 /* 506 * If we're at the beginning of the line and recognize a 507 * command character, then we echo locally. Otherwise, 508 * characters are echo'd remotely. If the command character 509 * is doubled, this acts as a force and local echo is 510 * suppressed. 511 */ 512 if (bol) { 513 bol = 0; 514 if (!noescape && c == escapechar) { 515 local = 1; 516 continue; 517 } 518 } else if (local) { 519 local = 0; 520 if (c == '.' || c == deftc.t_eofc) { 521 echo(c); 522 break; 523 } 524 if (c == defltc.t_suspc || c == defltc.t_dsuspc) { 525 bol = 1; 526 echo(c); 527 stop(c); 528 continue; 529 } 530 if (c != escapechar) 531#ifdef CRYPT 532#ifdef KERBEROS 533 if (doencrypt) 534 (void)des_enc_write(rem, 535 (char *)&escapechar, 1, 536 schedule, &cred.session); 537 else 538#endif 539#endif 540 (void)write(rem, &escapechar, 1); 541 } 542 543#ifdef CRYPT 544#ifdef KERBEROS 545 if (doencrypt) { 546 if (des_enc_write(rem, &c, 1, schedule, &cred.session) == 0) { 547 msg("line gone"); 548 break; 549 } 550 } else 551#endif 552#endif 553 if (write(rem, &c, 1) == 0) { 554 msg("line gone"); 555 break; 556 } 557 bol = c == defkill || c == deftc.t_eofc || 558 c == deftc.t_intrc || c == defltc.t_suspc || 559 c == '\r' || c == '\n'; 560 } 561} 562 563void 564echo(char c) 565{ 566 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 586stop(char cmdc) 587{ 588 mode(0); 589 (void)signal(SIGCHLD, SIG_IGN); 590 (void)kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP); 591 (void)signal(SIGCHLD, catch_child); 592 mode(1); 593 sigwinch(0); /* check for size changes */ 594} 595 596void 597sigwinch(int signo __unused) 598{ 599 struct winsize ws; 600 601 if (dosigwinch && get_window_size(0, &ws) == 0 && 602 bcmp(&ws, &winsize, sizeof(ws))) { 603 winsize = ws; 604 sendwindow(); 605 } 606} 607 608/* 609 * Send the window size to the server via the magic escape 610 */ 611void 612sendwindow(void) 613{ 614 struct winsize *wp; 615 char obuf[4 + sizeof (struct winsize)]; 616 617 wp = (struct winsize *)(obuf+4); 618 obuf[0] = 0377; 619 obuf[1] = 0377; 620 obuf[2] = 's'; 621 obuf[3] = 's'; 622 wp->ws_row = htons(winsize.ws_row); 623 wp->ws_col = htons(winsize.ws_col); 624 wp->ws_xpixel = htons(winsize.ws_xpixel); 625 wp->ws_ypixel = htons(winsize.ws_ypixel); 626 627#ifdef CRYPT 628#ifdef KERBEROS 629 if(doencrypt) 630 (void)des_enc_write(rem, obuf, sizeof(obuf), 631 schedule, &cred.session); 632 else 633#endif 634#endif 635 (void)write(rem, obuf, sizeof(obuf)); 636} 637 638/* 639 * reader: read from remote: line -> 1 640 */ 641#define READING 1 642#define WRITING 2 643 644jmp_buf rcvtop; 645int ppid, rcvcnt, rcvstate; 646char rcvbuf[8 * 1024]; 647 648void 649oob(int signo __unused) 650{ 651 struct sgttyb sb; 652 int atmark, n, out, rcvd; 653 char waste[BUFSIZ], mark; 654 655 out = O_RDWR; 656 rcvd = 0; 657 while (recv(rem, &mark, 1, MSG_OOB) < 0) { 658 switch (errno) { 659 case EWOULDBLOCK: 660 /* 661 * Urgent data not here yet. It may not be possible 662 * to send it yet if we are blocked for output and 663 * our input buffer is full. 664 */ 665 if (rcvcnt < (int)sizeof(rcvbuf)) { 666 n = read(rem, rcvbuf + rcvcnt, 667 sizeof(rcvbuf) - rcvcnt); 668 if (n <= 0) 669 return; 670 rcvd += n; 671 } else { 672 n = read(rem, waste, sizeof(waste)); 673 if (n <= 0) 674 return; 675 } 676 continue; 677 default: 678 return; 679 } 680 } 681 if (mark & TIOCPKT_WINDOW) { 682 /* Let server know about window size changes */ 683 (void)kill(ppid, SIGUSR1); 684 } 685 if (!eight && (mark & TIOCPKT_NOSTOP)) { 686 (void)ioctl(0, TIOCGETP, (char *)&sb); 687 sb.sg_flags &= ~CBREAK; 688 sb.sg_flags |= RAW; 689 (void)ioctl(0, TIOCSETN, (char *)&sb); 690 notc.t_stopc = -1; 691 notc.t_startc = -1; 692 (void)ioctl(0, TIOCSETC, (char *)¬c); 693 } 694 if (!eight && (mark & TIOCPKT_DOSTOP)) { 695 (void)ioctl(0, TIOCGETP, (char *)&sb); 696 sb.sg_flags &= ~RAW; 697 sb.sg_flags |= CBREAK; 698 (void)ioctl(0, TIOCSETN, (char *)&sb); 699 notc.t_stopc = deftc.t_stopc; 700 notc.t_startc = deftc.t_startc; 701 (void)ioctl(0, TIOCSETC, (char *)¬c); 702 } 703 if (mark & TIOCPKT_FLUSHWRITE) { 704 (void)ioctl(1, TIOCFLUSH, (char *)&out); 705 for (;;) { 706 if (ioctl(rem, SIOCATMARK, &atmark) < 0) { 707 warn("ioctl"); 708 break; 709 } 710 if (atmark) 711 break; 712 n = read(rem, waste, sizeof (waste)); 713 if (n <= 0) 714 break; 715 } 716 /* 717 * Don't want any pending data to be output, so clear the recv 718 * buffer. If we were hanging on a write when interrupted, 719 * don't want it to restart. If we were reading, restart 720 * anyway. 721 */ 722 rcvcnt = 0; 723 longjmp(rcvtop, 1); 724 } 725 726 /* oob does not do FLUSHREAD (alas!) */ 727 728 /* 729 * If we filled the receive buffer while a read was pending, longjmp 730 * to the top to restart appropriately. Don't abort a pending write, 731 * however, or we won't know how much was written. 732 */ 733 if (rcvd && rcvstate == READING) 734 longjmp(rcvtop, 1); 735} 736 737/* reader: read from remote: line -> 1 */ 738int 739reader(int omask) 740{ 741 int pid, n, remaining; 742 char *bufp; 743 744#if BSD >= 43 || defined(SUNOS4) 745 pid = getpid(); /* modern systems use positives for pid */ 746#else 747 pid = -getpid(); /* old broken systems use negatives */ 748#endif 749 (void)signal(SIGTTOU, SIG_IGN); 750 (void)signal(SIGURG, oob); 751 (void)signal(SIGUSR1, oob); /* When propogating SIGURG from parent */ 752 ppid = getppid(); 753 (void)fcntl(rem, F_SETOWN, pid); 754 (void)setjmp(rcvtop); 755 (void)sigsetmask(omask); 756 bufp = rcvbuf; 757 for (;;) { 758 while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) { 759 rcvstate = WRITING; 760 n = write(STDOUT_FILENO, bufp, remaining); 761 if (n < 0) { 762 if (errno != EINTR) 763 return (-1); 764 continue; 765 } 766 bufp += n; 767 } 768 bufp = rcvbuf; 769 rcvcnt = 0; 770 rcvstate = READING; 771 772#ifdef CRYPT 773#ifdef KERBEROS 774 if (doencrypt) 775 rcvcnt = des_enc_read(rem, rcvbuf, sizeof(rcvbuf), 776 schedule, &cred.session); 777 else 778#endif 779#endif 780 rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf)); 781 if (rcvcnt == 0) 782 return (0); 783 if (rcvcnt < 0) { 784 if (errno == EINTR) 785 continue; 786 warn("read"); 787 return (-1); 788 } 789 } 790} 791 792void 793mode(int f) 794{ 795 struct ltchars *ltc; 796 struct sgttyb sb; 797 struct tchars *tc; 798 int lflags; 799 800 (void)ioctl(0, TIOCGETP, (char *)&sb); 801 (void)ioctl(0, TIOCLGET, (char *)&lflags); 802 switch(f) { 803 case 0: 804 sb.sg_flags &= ~(CBREAK|RAW|TBDELAY); 805 sb.sg_flags |= defflags|tabflag; 806 tc = &deftc; 807 ltc = &defltc; 808 sb.sg_kill = defkill; 809 sb.sg_erase = deferase; 810 lflags = deflflags; 811 break; 812 case 1: 813 sb.sg_flags |= (eight ? RAW : CBREAK); 814 sb.sg_flags &= ~defflags; 815 /* preserve tab delays, but turn off XTABS */ 816 if ((sb.sg_flags & TBDELAY) == XTABS) 817 sb.sg_flags &= ~TBDELAY; 818 tc = ¬c; 819 ltc = &noltc; 820 sb.sg_kill = sb.sg_erase = -1; 821 if (litout) 822 lflags |= LLITOUT; 823 break; 824 default: 825 return; 826 } 827 (void)ioctl(0, TIOCSLTC, (char *)ltc); 828 (void)ioctl(0, TIOCSETC, (char *)tc); 829 (void)ioctl(0, TIOCSETN, (char *)&sb); 830 (void)ioctl(0, TIOCLSET, (char *)&lflags); 831} 832 833void 834lostpeer(int signo __unused) 835{ 836 (void)signal(SIGPIPE, SIG_IGN); 837 msg("\007connection closed."); 838 done(1); 839} 840 841/* copy SIGURGs to the child process via SIGUSR1. */ 842void 843copytochild(int signo __unused) 844{ 845 (void)kill(child, SIGUSR1); 846} 847 848void 849msg(const char *str) 850{ 851 (void)fprintf(stderr, "rlogin: %s\r\n", str); 852} 853 854void 855usage(void) 856{ 857 (void)fprintf(stderr, 858 "usage: rlogin [-46%s]%s[-e char] [-i localname] [-l username] host\n", 859#ifdef KERBEROS 860#ifdef CRYPT 861 "8DEKLdx", " [-k realm] "); 862#else 863 "8DEKLd", " [-k realm] "); 864#endif 865#else 866 "8DEKLd", " "); 867#endif 868 exit(1); 869} 870 871u_int 872getescape(char *p) 873{ 874 long val; 875 int len; 876 877 if ((len = strlen(p)) == 1) /* use any single char, including '\' */ 878 return ((u_int)*p); 879 /* otherwise, \nnn */ 880 if (*p == '\\' && len >= 2 && len <= 4) { 881 val = strtol(++p, NULL, 8); 882 for (;;) { 883 if (!*++p) 884 return ((u_int)val); 885 if (*p < '0' || *p > '8') 886 break; 887 } 888 } 889 msg("illegal option value -- e"); 890 usage(); 891 /* NOTREACHED */ 892} 893