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 42__attribute__((__used__)) 43static const char copyright[] = 44"@(#) Copyright (c) 1983, 1990, 1993\n\ 45 The Regents of the University of California. All rights reserved.\n"; 46#endif /* not lint */ 47 48#if 0 49#ifndef lint 50static const char sccsid[] = "@(#)rlogin.c 8.1 (Berkeley) 6/6/93"; 51#endif /* not lint */ 52#endif 53 54#include <sys/cdefs.h> 55__FBSDID("$FreeBSD: src/usr.bin/rlogin/rlogin.c,v 1.40 2005/11/13 21:03:56 dwmalone Exp $"); 56 57/* 58 * rlogin - remote login 59 */ 60 61#include <sys/param.h> 62#include <sys/ioctl.h> 63#include <sys/socket.h> 64#include <sys/time.h> 65#include <sys/resource.h> 66#include <sys/wait.h> 67 68#include <netinet/in.h> 69#include <netinet/in_systm.h> 70#include <netinet/ip.h> 71#include <netinet/tcp.h> 72 73#include <err.h> 74#include <errno.h> 75#include <fcntl.h> 76#ifndef __APPLE__ 77#include <libutil.h> 78#endif 79#include <netdb.h> 80#include <paths.h> 81#include <pwd.h> 82#include <setjmp.h> 83#include <termios.h> 84#include <signal.h> 85#include <stdio.h> 86#include <stdlib.h> 87#include <string.h> 88#include <unistd.h> 89 90#include <stdarg.h> 91 92#if defined(KERBEROS) 93#include <kerberosIV/des.h> 94#include <kerberosIV/krb.h> 95 96#include "krb.h" 97 98CREDENTIALS cred; 99Key_schedule schedule; 100int use_kerberos = 1, doencrypt; 101char dst_realm_buf[REALM_SZ], *dest_realm = NULL; 102#endif /* KERBEROS */ 103 104#ifndef TIOCPKT_WINDOW 105#define TIOCPKT_WINDOW 0x80 106#endif 107 108/* concession to Sun */ 109#ifndef SIGUSR1 110#define SIGUSR1 30 111#endif 112 113int eight, rem; 114struct termios deftty; 115 116int family = PF_UNSPEC; 117 118int noescape; 119u_char escapechar = '~'; 120 121#define get_window_size(fd, wp) ioctl(fd, TIOCGWINSZ, wp) 122struct winsize winsize; 123 124void catch_child(int); 125void copytochild(int); 126#ifdef __APPLE__ 127void doit(sigset_t *) __dead2; 128#else 129void doit(long) __dead2; 130#endif 131void done(int) __dead2; 132void echo(char); 133u_int getescape(const char *); 134void lostpeer(int); 135void mode(int); 136void msg(const char *); 137void oob(int); 138#ifdef __APPLE__ 139int reader(sigset_t *); 140#else 141int reader(int); 142#endif 143void sendwindow(void); 144void setsignal(int); 145void sigwinch(int); 146void stop(char); 147void usage(void) __dead2; 148void writer(void); 149void writeroob(int); 150 151#if defined(KERBEROS) 152void warning(const char *, ...); 153#endif 154 155int 156main(int argc, char *argv[]) 157{ 158 struct passwd *pw; 159 struct servent *sp; 160 struct termios tty; 161#ifndef __APPLE__ 162 long omask; 163#else 164 sigset_t smask; 165 struct sigaction sa; 166#endif 167 int argoff, ch, dflag, Dflag, one; 168 uid_t uid; 169 char *host, *localname, *p, *user, term[1024]; 170 speed_t ospeed; 171 struct sockaddr_storage ss; 172 socklen_t sslen; 173 size_t len, len2; 174 int i; 175 176 argoff = dflag = Dflag = 0; 177 one = 1; 178 host = localname = user = NULL; 179 180#ifdef __APPLE__ 181 if (argv[0] == NULL) 182 usage(); 183#endif 184 if ((p = rindex(argv[0], '/'))) 185 ++p; 186 else 187 p = argv[0]; 188 189 if (strcmp(p, "rlogin")) 190 host = p; 191 192 /* handle "rlogin host flags" */ 193 if (!host && argc > 2 && argv[1][0] != '-') { 194 host = argv[1]; 195 argoff = 1; 196 } 197 198#if defined(KERBEROS) 199#define OPTIONS "468EKLde:k:l:x" 200#else 201#define OPTIONS "468DEde:i:l:" 202#endif 203 while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != -1) 204 switch(ch) { 205 case '4': 206 family = PF_INET; 207 break; 208 209 case '6': 210 family = PF_INET6; 211 break; 212 213 case '8': 214 eight = 1; 215 break; 216 case 'D': 217 Dflag = 1; 218 break; 219 case 'E': 220 noescape = 1; 221 break; 222#if defined(KERBEROS) 223 case 'K': 224 use_kerberos = 0; 225 break; 226 case 'L': 227 litout = 1; 228 break; 229#endif 230 case 'd': 231 dflag = 1; 232 break; 233 case 'e': 234 noescape = 0; 235 escapechar = getescape(optarg); 236 break; 237 case 'i': 238 if (getuid() != 0) 239 errx(1, "-i user: permission denied"); 240 localname = optarg; 241#if defined(KERBEROS) 242 case 'k': 243 dest_realm = dst_realm_buf; 244 (void)strncpy(dest_realm, optarg, REALM_SZ); 245 break; 246#endif 247 case 'l': 248 user = optarg; 249 break; 250#if defined(KERBEROS) && defined(CRYPT) 251 case 'x': 252 doencrypt = 1; 253 des_set_key(cred.session, schedule); 254 break; 255#endif 256 case '?': 257 default: 258 usage(); 259 } 260 optind += argoff; 261 262 /* if haven't gotten a host yet, do so */ 263 if (!host && !(host = argv[optind++])) 264 usage(); 265 266 if (argv[optind]) 267 usage(); 268 269 if (!(pw = getpwuid(uid = getuid()))) 270 errx(1, "unknown user id"); 271#ifdef __APPLE__ 272 /* Accept user1@host format, though "-l user2" overrides user1 */ 273 p = strchr(host, '@'); 274 if (p) { 275 *p = '\0'; 276 if (!user && p > host) 277 user = host; 278 host = p + 1; 279 if (*host == '\0') 280 usage(); 281 } 282#endif 283 if (!user) 284 user = pw->pw_name; 285 if (!localname) 286 localname = pw->pw_name; 287 288 sp = NULL; 289#if defined(KERBEROS) 290 if (use_kerberos) { 291 sp = getservbyname((doencrypt ? "eklogin" : "klogin"), "tcp"); 292 if (sp == NULL) { 293 use_kerberos = 0; 294 warning("can't get entry for %s/tcp service", 295 doencrypt ? "eklogin" : "klogin"); 296 } 297 } 298 if (sp == NULL) 299#endif 300 sp = getservbyname("login", "tcp"); 301 if (sp == NULL) 302 errx(1, "login/tcp: unknown service"); 303 304 if ((p = getenv("TERM")) != NULL) 305 (void)strlcpy(term, p, sizeof(term)); 306#if __APPLE__ 307 else 308 (void)strcpy(term, "network"); 309#endif 310 len = strlen(term); 311 if (len < (sizeof(term) - 1) && tcgetattr(0, &tty) == 0) { 312 /* start at 2 to include the / */ 313 for (ospeed = i = cfgetospeed(&tty), len2 = 2; i > 9; len2++) 314 i /= 10; 315 if (len + len2 < sizeof(term)) 316 (void)snprintf(term + len, len2 + 1, "/%ld", ospeed); 317 } 318 319 (void)get_window_size(0, &winsize); 320 321#ifdef __APPLE__ 322 sigemptyset(&sa.sa_mask); 323 sa.sa_flags = SA_RESTART; 324 sa.sa_handler = lostpeer; 325 (void)sigaction(SIGPIPE, &sa, (struct sigaction *) 0); 326#else 327 (void)signal(SIGPIPE, lostpeer); 328#endif 329 /* will use SIGUSR1 for window size hack, so hold it off */ 330#ifdef __APPLE__ 331 sigemptyset(&smask); 332 sigaddset(&smask, SIGURG); 333 sigaddset(&smask, SIGUSR1); 334 (void)sigprocmask(SIG_SETMASK, &smask, &smask); 335#else 336 omask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1)); 337#endif 338 /* 339 * We set SIGURG and SIGUSR1 below so that an 340 * incoming signal will be held pending rather than being 341 * discarded. Note that these routines will be ready to get 342 * a signal by the time that they are unblocked below. 343 */ 344#ifdef __APPLE__ 345 sa.sa_handler = copytochild; 346 (void)sigaction(SIGURG, &sa, (struct sigaction *) 0); 347 sa.sa_handler = writeroob; 348 (void)sigaction(SIGUSR1, &sa, (struct sigaction *) 0); 349#else 350 (void)signal(SIGURG, copytochild); 351 (void)signal(SIGUSR1, writeroob); 352#endif 353 354#if defined(KERBEROS) 355try_connect: 356 if (use_kerberos) { 357 struct hostent *hp; 358 359 /* Fully qualify hostname (needed for krb_realmofhost). */ 360 hp = gethostbyname(host); 361 if (hp != NULL && !(host = strdup(hp->h_name))) 362 errx(1, "%s", strerror(ENOMEM)); 363 364 rem = KSUCCESS; 365 errno = 0; 366 if (dest_realm == NULL) 367 dest_realm = krb_realmofhost(host); 368 369#if defined(CRYPT) 370 if (doencrypt) 371 rem = krcmd_mutual(&host, sp->s_port, user, term, 0, 372 dest_realm, &cred, schedule); 373 else 374#endif /* CRYPT */ 375 rem = krcmd(&host, sp->s_port, user, term, 0, 376 dest_realm); 377 if (rem < 0) { 378 use_kerberos = 0; 379 sp = getservbyname("login", "tcp"); 380 if (sp == NULL) 381 errx(1, "unknown service login/tcp"); 382 if (errno == ECONNREFUSED) 383 warning("remote host doesn't support Kerberos"); 384 if (errno == ENOENT) 385 warning("can't provide Kerberos auth data"); 386 goto try_connect; 387 } 388 } else { 389#if defined(CRYPT) 390 if (doencrypt) 391 errx(1, "the -x flag requires Kerberos authentication"); 392#endif /* CRYPT */ 393 rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0); 394 } 395#else /* KERBEROS */ 396 rem = rcmd_af(&host, sp->s_port, localname, user, term, 0, family); 397// rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0); 398#endif /* KERBEROS */ 399 400 if (rem < 0) 401 exit(1); 402 403 if (dflag && 404 setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0) 405 warn("setsockopt"); 406 if (Dflag && 407 setsockopt(rem, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)) < 0) 408 warn("setsockopt NODELAY (ignored)"); 409 410 sslen = sizeof(ss); 411 one = IPTOS_LOWDELAY; 412 if (getsockname(rem, (struct sockaddr *)&ss, &sslen) == 0 && 413 ss.ss_family == AF_INET) { 414 if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, 415 sizeof(int)) < 0) 416 warn("setsockopt TOS (ignored)"); 417 } else 418 if (ss.ss_family == AF_INET) 419 warn("setsockopt getsockname failed"); 420 421 (void)setuid(uid); 422#ifdef __APPLE__ 423 doit(&smask); 424#else 425 doit(omask); 426#endif 427 /*NOTREACHED*/ 428} 429 430int child; 431 432void 433#ifdef __APPLE__ 434doit(sigset_t *omask) 435#else 436doit(long omask) 437#endif 438{ 439 440// int i; 441// for (i = 0; i < NCCS; i++) 442// nott.c_cc[i] = _POSIX_VDISABLE; 443// tcgetattr(0, &deftt); 444// nott.c_cc[VSTART] = deftt.c_cc[VSTART]; 445// nott.c_cc[VSTOP] = deftt.c_cc[VSTOP]; 446#ifdef __APPLE__ 447 struct sigaction sa; 448 449 sigemptyset(&sa.sa_mask); 450 sa.sa_flags = SA_RESTART; 451 sa.sa_handler = SIG_IGN; 452 (void)sigaction(SIGINT, &sa, (struct sigaction *) 0); 453#else 454 (void)signal(SIGINT, SIG_IGN); 455#endif 456 setsignal(SIGHUP); 457 setsignal(SIGQUIT); 458 mode(1); 459 child = fork(); 460 if (child == -1) { 461 warn("fork"); 462 done(1); 463 } 464 if (child == 0) { 465 if (reader(omask) == 0) { 466 msg("connection closed"); 467 exit(0); 468 } 469 sleep(1); 470 msg("\007connection closed"); 471 exit(1); 472 } 473 474 /* 475 * We may still own the socket, and may have a pending SIGURG (or might 476 * receive one soon) that we really want to send to the reader. When 477 * one of these comes in, the trap copytochild simply copies such 478 * signals to the child. We can now unblock SIGURG and SIGUSR1 479 * that were set above. 480 */ 481#ifdef __APPLE__ 482 (void)sigprocmask(SIG_SETMASK, omask, (sigset_t *) 0); 483 sa.sa_handler = catch_child; 484 (void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0); 485#else 486 (void)sigsetmask(omask); 487 (void)signal(SIGCHLD, catch_child); 488#endif 489 writer(); 490 msg("closed connection"); 491 done(0); 492} 493 494/* trap a signal, unless it is being ignored. */ 495void 496setsignal(int sig) 497{ 498#ifdef __APPLE__ 499 struct sigaction sa; 500 sigset_t sigs; 501 502 sigemptyset(&sigs); 503 sigaddset(&sigs, sig); 504 sigprocmask(SIG_BLOCK, &sigs, &sigs); 505 506 sigemptyset(&sa.sa_mask); 507 sa.sa_handler = exit; 508 sa.sa_flags = SA_RESTART; 509 (void)sigaction(sig, &sa, &sa); 510 if (sa.sa_handler == SIG_IGN) 511 (void)sigaction(sig, &sa, (struct sigaction *) 0); 512 513 (void)sigprocmask(SIG_SETMASK, &sigs, (sigset_t *) 0); 514#else 515 int omask = sigblock(sigmask(sig)); 516 517 if (signal(sig, exit) == SIG_IGN) 518 (void)signal(sig, SIG_IGN); 519 (void)sigsetmask(omask); 520#endif 521} 522 523void 524done(int status) 525{ 526 int w, wstatus; 527 528 mode(0); 529 if (child > 0) { 530 /* make sure catch_child does not snap it up */ 531#if __APPLE__ 532 struct sigaction sa; 533 sigemptyset(&sa.sa_mask); 534 sa.sa_handler = SIG_DFL; 535 sa.sa_flags = 0; 536 (void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0); 537#else 538 (void)signal(SIGCHLD, SIG_DFL); 539#endif 540 if (kill(child, SIGKILL) >= 0) 541 while ((w = wait(&wstatus)) > 0 && w != child); 542 } 543 exit(status); 544} 545 546int dosigwinch; 547 548/* 549 * This is called when the reader process gets the out-of-band (urgent) 550 * request to turn on the window-changing protocol. 551 */ 552/* ARGSUSED */ 553void 554writeroob(int signo __unused) 555{ 556 if (dosigwinch == 0) { 557 sendwindow(); 558#ifdef __APPLE__ 559 struct sigaction sa; 560 sigemptyset(&sa.sa_mask); 561 sa.sa_handler = sigwinch; 562 sa.sa_flags = SA_RESTART; 563 (void)sigaction(SIGWINCH, &sa, (struct sigaction *) 0); 564#else 565 (void)signal(SIGWINCH, sigwinch); 566#endif 567 } 568 dosigwinch = 1; 569} 570 571/* ARGSUSED */ 572void 573catch_child(int signo __unused) 574{ 575 pid_t pid; 576 int status; 577 578 for (;;) { 579 pid = wait3(&status, WNOHANG|WUNTRACED, NULL); 580 if (pid == 0) 581 return; 582 /* if the child (reader) dies, just quit */ 583 if (pid < 0 || (pid == child && !WIFSTOPPED(status))) 584 done(WTERMSIG(status) | WEXITSTATUS(status)); 585 } 586 /* NOTREACHED */ 587} 588 589/* 590 * writer: write to remote: 0 -> line. 591 * ~. terminate 592 * ~^Z suspend rlogin process. 593 * ~<delayed-suspend char> suspend rlogin process, but leave reader alone. 594 */ 595void 596writer(void) 597{ 598 int bol, local, n; 599 char c; 600 601 bol = 1; /* beginning of line */ 602 local = 0; 603 for (;;) { 604 n = read(STDIN_FILENO, &c, 1); 605 if (n <= 0) { 606 if (n < 0 && errno == EINTR) 607 continue; 608 break; 609 } 610 /* 611 * If we're at the beginning of the line and recognize a 612 * command character, then we echo locally. Otherwise, 613 * characters are echo'd remotely. If the command character 614 * is doubled, this acts as a force and local echo is 615 * suppressed. 616 */ 617 if (bol) { 618 bol = 0; 619 if (!noescape && c == escapechar) { 620 local = 1; 621 continue; 622 } 623 } else if (local) { 624 local = 0; 625 if (c == '.' || CCEQ(deftty.c_cc[VEOF], c)) { 626 echo(c); 627 break; 628 } 629 if (CCEQ(deftty.c_cc[VSUSP], c) || 630 CCEQ(deftty.c_cc[VDSUSP], c)) { 631 bol = 1; 632 echo(c); 633 stop(c); 634 continue; 635 } 636 if (c != escapechar) 637#if defined(KERBEROS) && defined(CRYPT) 638 if (doencrypt) 639 (void)des_write(rem, 640 (char *)&escapechar, 1); 641 else 642#endif 643 (void)write(rem, &escapechar, 1); 644 } 645 646#if defined(KERBEROS) && defined(CRYPT) 647 if (doencrypt) { 648 if (des_write(rem, &c, 1) == 0) { 649 msg("line gone"); 650 break; 651 } 652 } else 653#endif 654 if (write(rem, &c, 1) == 0) { 655 msg("line gone"); 656 break; 657 } 658 bol = CCEQ(deftty.c_cc[VKILL], c) || 659 CCEQ(deftty.c_cc[VEOF], c) || 660 CCEQ(deftty.c_cc[VINTR], c) || 661 CCEQ(deftty.c_cc[VSUSP], c) || 662 c == '\r' || c == '\n'; 663 } 664} 665 666void 667echo(char c) 668{ 669 char *p; 670 char buf[8]; 671 672 p = buf; 673 c &= 0177; 674 *p++ = escapechar; 675 if (c < ' ') { 676 *p++ = '^'; 677 *p++ = c + '@'; 678 } else if (c == 0177) { 679 *p++ = '^'; 680 *p++ = '?'; 681 } else 682 *p++ = c; 683 *p++ = '\r'; 684 *p++ = '\n'; 685 (void)write(STDOUT_FILENO, buf, p - buf); 686} 687 688void 689stop(char cmdc) 690{ 691 mode(0); 692#ifdef __APPLE__ 693 struct sigaction sa; 694 695 sigemptyset(&sa.sa_mask); 696 sa.sa_handler = SIG_IGN; 697 sa.sa_flags = SA_RESTART; 698 (void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0); 699#else 700 (void)signal(SIGCHLD, SIG_IGN); 701#endif 702 (void)kill(CCEQ(deftty.c_cc[VSUSP], cmdc) ? 0 : getpid(), SIGTSTP); 703#ifdef __APPLE__ 704 sa.sa_handler = catch_child; 705 (void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0); 706#else 707 (void)signal(SIGCHLD, catch_child); 708#endif 709 mode(1); 710 sigwinch(0); /* check for size changes */ 711} 712 713/* ARGSUSED */ 714void 715sigwinch(int signo __unused) 716{ 717 struct winsize ws; 718 719 if (dosigwinch && get_window_size(0, &ws) == 0 && 720 bcmp(&ws, &winsize, sizeof(ws))) { 721 winsize = ws; 722 sendwindow(); 723 } 724} 725 726/* 727 * Send the window size to the server via the magic escape 728 */ 729void 730sendwindow(void) 731{ 732 struct winsize *wp; 733 char obuf[4 + sizeof (struct winsize)]; 734 735 wp = (struct winsize *)(obuf+4); 736 obuf[0] = 0377; 737 obuf[1] = 0377; 738 obuf[2] = 's'; 739 obuf[3] = 's'; 740 wp->ws_row = htons(winsize.ws_row); 741 wp->ws_col = htons(winsize.ws_col); 742 wp->ws_xpixel = htons(winsize.ws_xpixel); 743 wp->ws_ypixel = htons(winsize.ws_ypixel); 744 745#if defined(KERBEROS) && defined(CRYPT) 746 if(doencrypt) 747 (void)des_write(rem, obuf, sizeof(obuf)); 748 else 749#endif 750 (void)write(rem, obuf, sizeof(obuf)); 751} 752 753/* 754 * reader: read from remote: line -> 1 755 */ 756#define READING 1 757#define WRITING 2 758 759jmp_buf rcvtop; 760int rcvcnt, rcvstate; 761pid_t ppid; 762char rcvbuf[8 * 1024]; 763 764/* ARGSUSED */ 765void 766oob(int signo __unused) 767{ 768 struct termios tty; 769 int atmark, n, rcvd; 770 char waste[BUFSIZ], mark; 771 772 rcvd = 0; 773 while (recv(rem, &mark, 1, MSG_OOB) < 0) { 774 switch (errno) { 775 case EWOULDBLOCK: 776 /* 777 * Urgent data not here yet. It may not be possible 778 * to send it yet if we are blocked for output and 779 * our input buffer is full. 780 */ 781 if (rcvcnt < (int)sizeof(rcvbuf)) { 782 n = read(rem, rcvbuf + rcvcnt, 783 sizeof(rcvbuf) - rcvcnt); 784 if (n <= 0) 785 return; 786 rcvd += n; 787 } else { 788 n = read(rem, waste, sizeof(waste)); 789 if (n <= 0) 790 return; 791 } 792 continue; 793 default: 794 return; 795 } 796 } 797 if (mark & TIOCPKT_WINDOW) { 798 /* Let server know about window size changes */ 799 (void)kill(ppid, SIGUSR1); 800 } 801 if (!eight && (mark & TIOCPKT_NOSTOP)) { 802 (void)tcgetattr(0, &tty); 803 tty.c_iflag &= ~IXON; 804 (void)tcsetattr(0, TCSANOW, &tty); 805// tt.c_iflag &= ~(IXON | IXOFF); 806// tt.c_cc[VSTOP] = _POSIX_VDISABLE; 807// tt.c_cc[VSTART] = _POSIX_VDISABLE; 808 } 809 if (!eight && (mark & TIOCPKT_DOSTOP)) { 810 (void)tcgetattr(0, &tty); 811 tty.c_iflag |= (deftty.c_iflag & IXON); 812 (void)tcsetattr(0, TCSANOW, &tty); 813// tt.c_iflag |= (IXON|IXOFF); 814// tt.c_cc[VSTOP] = deftt.c_cc[VSTOP]; 815// tt.c_cc[VSTART] = deftt.c_cc[VSTART]; 816 } 817 if (mark & TIOCPKT_FLUSHWRITE) { 818 (void)tcflush(1, TCIOFLUSH); 819 for (;;) { 820 if (ioctl(rem, SIOCATMARK, &atmark) < 0) { 821 warn("ioctl"); 822 break; 823 } 824 if (atmark) 825 break; 826 n = read(rem, waste, sizeof (waste)); 827 if (n <= 0) 828 break; 829 } 830 /* 831 * Don't want any pending data to be output, so clear the recv 832 * buffer. If we were hanging on a write when interrupted, 833 * don't want it to restart. If we were reading, restart 834 * anyway. 835 */ 836 rcvcnt = 0; 837 longjmp(rcvtop, 1); 838 } 839 840 /* oob does not do FLUSHREAD (alas!) */ 841 842 /* 843 * If we filled the receive buffer while a read was pending, longjmp 844 * to the top to restart appropriately. Don't abort a pending write, 845 * however, or we won't know how much was written. 846 */ 847 if (rcvd && rcvstate == READING) 848 longjmp(rcvtop, 1); 849} 850 851/* reader: read from remote: line -> 1 */ 852int 853#if __APPLE__ 854reader(sigset_t *smask) 855#else 856reader(int omask) 857#endif 858{ 859 int n, remaining; 860 char *bufp; 861 pid_t pid; 862 863 pid = getpid(); 864#if __APPLE__ 865 struct sigaction sa; 866 867 sigemptyset(&sa.sa_mask); 868 sa.sa_flags = SA_RESTART; 869 sa.sa_handler = SIG_IGN; 870 (void)sigaction(SIGTTOU, &sa, (struct sigaction *) 0); 871 sa.sa_handler = oob; 872 (void)sigaction(SIGURG, &sa, (struct sigaction *) 0); 873 (void)sigaction(SIGUSR1, &sa, (struct sigaction *) 0); 874#else 875 (void)signal(SIGTTOU, SIG_IGN); 876 (void)signal(SIGURG, oob); 877 (void)signal(SIGUSR1, oob); /* When propogating SIGURG from parent */ 878#endif 879 ppid = getppid(); 880 (void)fcntl(rem, F_SETOWN, pid); 881 (void)setjmp(rcvtop); 882#if __APPLE__ 883 (void)sigprocmask(SIG_SETMASK, smask, (sigset_t *) 0); 884#else 885 (void)sigsetmask(omask); 886#endif 887 bufp = rcvbuf; 888 for (;;) { 889 while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) { 890 rcvstate = WRITING; 891 n = write(STDOUT_FILENO, bufp, remaining); 892 if (n < 0) { 893 if (errno != EINTR) 894 return (-1); 895 continue; 896 } 897 bufp += n; 898 } 899 bufp = rcvbuf; 900 rcvcnt = 0; 901 rcvstate = READING; 902 903#if defined(KERBEROS) && defined(CRYPT) 904 if (doencrypt) 905 rcvcnt = des_read(rem, rcvbuf, sizeof(rcvbuf)); 906 else 907#endif 908 rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf)); 909 if (rcvcnt == 0) 910 return (0); 911 if (rcvcnt < 0) { 912 if (errno == EINTR) 913 continue; 914 warn("read"); 915 return (-1); 916 } 917 } 918} 919 920void 921mode(int f) 922{ 923 struct termios tty; 924 925 switch (f) { 926 case 0: 927 (void)tcsetattr(0, TCSANOW, &deftty); 928// (void)tcsetattr(0, TCSADRAIN, &deftty); 929 break; 930 case 1: 931 (void)tcgetattr(0, &deftty); 932 tty = deftty; 933 /* This is loosely derived from sys/kern/tty_compat.c. */ 934 tty.c_lflag &= ~(ECHO|ICANON|ISIG|IEXTEN); 935 tty.c_iflag &= ~ICRNL; 936 tty.c_oflag &= ~OPOST; 937 tty.c_cc[VMIN] = 1; 938 tty.c_cc[VTIME] = 0; 939 if (eight) { 940 tty.c_iflag &= IXOFF; 941 tty.c_cflag &= ~(CSIZE|PARENB); 942 tty.c_cflag |= CS8; 943// tt.c_iflag &= ~(IXON | IXOFF | ISTRIP); 944// tt.c_cc[VSTOP] = _POSIX_VDISABLE; 945// tt.c_cc[VSTART] = _POSIX_VDISABLE; 946 } 947 (void)tcsetattr(0, TCSANOW, &tty); 948// tcsetattr(0, TCSADRAIN, &tt); 949 break; 950 default: 951 return; 952 } 953} 954 955/* ARGSUSED */ 956void 957lostpeer(int signo __unused) 958{ 959#ifdef __APPLE__ 960 struct sigaction sa; 961 962 sigemptyset(&sa.sa_mask); 963 sa.sa_flags = SA_RESTART; 964 sa.sa_handler = SIG_IGN; 965 (void)sigaction(SIGPIPE, &sa, (struct sigaction *) 0); 966#else 967 (void)signal(SIGPIPE, SIG_IGN); 968#endif 969 msg("\007connection closed"); 970 done(1); 971} 972 973/* copy SIGURGs to the child process via SIGUSR1. */ 974/* ARGSUSED */ 975void 976copytochild(int signo __unused) 977{ 978 (void)kill(child, SIGUSR1); 979} 980 981void 982msg(const char *str) 983{ 984 (void)fprintf(stderr, "rlogin: %s\r\n", str); 985} 986 987#if defined(KERBEROS) 988/* VARARGS */ 989void 990warning(const char *fmt, ...) 991{ 992 va_list ap; 993 994 (void)fprintf(stderr, "rlogin: warning, using standard rlogin: "); 995 va_start(ap, fmt); 996 vfprintf(stderr, fmt, ap); 997 va_end(ap); 998 (void)fprintf(stderr, ".\n"); 999} 1000#endif 1001 1002void 1003usage(void) 1004{ 1005 (void)fprintf(stderr, 1006#ifdef __APPLE__ 1007 "usage: rlogin [-46%s]%s[-e char] [-i localname] [-l username] [username@]host\n", 1008#else 1009 "usage: rlogin [-46%s]%s[-e char] [-i localname] [-l username] host\n", 1010#endif 1011#if defined(KERBEROS) && defined(CRYPT) 1012 "8EKLx", " [-k realm] "); 1013#elif defined(KERBEROS) 1014 "8EKL", " [-k realm] "); 1015#else 1016 "8DEd", " "); 1017#endif 1018 exit(1); 1019} 1020 1021u_int 1022getescape(const char *p) 1023{ 1024 long val; 1025 size_t len; 1026 1027 if ((len = strlen(p)) == 1) /* use any single char, including '\' */ 1028 return ((u_int)*p); 1029 /* otherwise, \nnn */ 1030 if (*p == '\\' && len >= 2 && len <= 4) { 1031 val = strtol(++p, NULL, 8); 1032 for (;;) { 1033 if (!*++p) 1034 return ((u_int)val); 1035 if (*p < '0' || *p > '8') 1036 break; 1037 } 1038 } 1039 msg("illegal option value -- e"); 1040 usage(); 1041 /* NOTREACHED */ 1042} 1043