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