rlogin.c revision 40103
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.17 1998/03/26 18:03:41 markm 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, *p, *user, term[1024]; 154#ifdef KERBEROS 155 char *k; 156#endif 157 158 argoff = dflag = Dflag = 0; 159 one = 1; 160 host = 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:k:l:x" 178#else 179#define OPTIONS "8DEKLde: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#ifdef KERBEROS 208 case 'k': 209 dest_realm = dst_realm_buf; 210 (void)strncpy(dest_realm, optarg, REALM_SZ); 211 break; 212#endif 213 case 'l': 214 user = optarg; 215 break; 216#ifdef CRYPT 217#ifdef KERBEROS 218 case 'x': 219 doencrypt = 1; 220 break; 221#endif 222#endif 223 case '?': 224 default: 225 usage(); 226 } 227 optind += argoff; 228 229 /* if haven't gotten a host yet, do so */ 230 if (!host && !(host = argv[optind++])) 231 usage(); 232 233 if (argv[optind]) 234 usage(); 235 236 if (!(pw = getpwuid(uid = getuid()))) 237 errx(1, "unknown user id"); 238 if (!user) 239 user = pw->pw_name; 240 241 sp = NULL; 242#ifdef KERBEROS 243 k = auth_getval("auth_list"); 244 if (k && !strstr(k, "kerberos")) 245 use_kerberos = 0; 246 if (use_kerberos) { 247 sp = getservbyname((doencrypt ? "eklogin" : "klogin"), "tcp"); 248 if (sp == NULL) { 249 use_kerberos = 0; 250 warn("can't get entry for %s/tcp service", 251 doencrypt ? "eklogin" : "klogin"); 252 } 253 } 254#endif 255 if (sp == NULL) 256 sp = getservbyname("login", "tcp"); 257 if (sp == NULL) 258 errx(1, "login/tcp: unknown service"); 259 260#define MAX_TERM_LENGTH (sizeof(term) - 1 - MAX_SPEED_LENGTH - 1) 261 262 (void)strncpy(term, (p = getenv("TERM")) ? p : "network", 263 MAX_TERM_LENGTH); 264 term[MAX_TERM_LENGTH] = '\0'; 265 if (ioctl(0, TIOCGETP, &ttyb) == 0) { 266 (void)strcat(term, "/"); 267 (void)strcat(term, speeds[(int)ttyb.sg_ospeed]); 268 } 269 270 (void)get_window_size(0, &winsize); 271 272 (void)signal(SIGPIPE, lostpeer); 273 /* will use SIGUSR1 for window size hack, so hold it off */ 274 omask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1)); 275 /* 276 * We set SIGURG and SIGUSR1 below so that an 277 * incoming signal will be held pending rather than being 278 * discarded. Note that these routines will be ready to get 279 * a signal by the time that they are unblocked below. 280 */ 281 (void)signal(SIGURG, copytochild); 282 (void)signal(SIGUSR1, writeroob); 283 284#ifdef KERBEROS 285 if (use_kerberos) { 286 setuid(getuid()); 287 rem = KSUCCESS; 288 errno = 0; 289 if (dest_realm == NULL) 290 dest_realm = krb_realmofhost(host); 291 292#ifdef CRYPT 293 if (doencrypt) { 294 rem = krcmd_mutual(&host, sp->s_port, user, term, 0, 295 dest_realm, &cred, schedule); 296 des_set_key(&cred.session, schedule); 297 } else 298#endif /* CRYPT */ 299 rem = krcmd(&host, sp->s_port, user, term, 0, 300 dest_realm); 301 if (rem < 0) { 302 int i; 303 char **newargv; 304 305 sp = getservbyname("login", "tcp"); 306 if (sp == NULL) 307 errx(1, "unknown service login/tcp"); 308 if (errno == ECONNREFUSED) 309 warn("remote host doesn't support Kerberos"); 310 if (errno == ENOENT) 311 warn("can't provide Kerberos auth data"); 312 newargv = malloc((argc + 2) * sizeof(*newargv)); 313 if (newargv == NULL) 314 err(1, "malloc"); 315 newargv[0] = argv[0]; 316 newargv[1] = "-K"; 317 for(i = 1; i < argc; ++i) 318 newargv[i + 1] = argv[i]; 319 newargv[argc + 1] = NULL; 320 execv(_PATH_RLOGIN, newargv); 321 } 322 } else { 323#ifdef CRYPT 324 if (doencrypt) 325 errx(1, "the -x flag requires Kerberos authentication"); 326#endif /* CRYPT */ 327 rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0); 328 } 329#else 330 rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0); 331#endif /* KERBEROS */ 332 333 if (rem < 0) 334 exit(1); 335 336 if (dflag && 337 setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0) 338 warn("setsockopt"); 339 if (Dflag && 340 setsockopt(rem, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)) < 0) 341 warn("setsockopt NODELAY (ignored)"); 342 343 one = IPTOS_LOWDELAY; 344 if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, sizeof(int)) < 0) 345 warn("setsockopt TOS (ignored)"); 346 347 (void)setuid(uid); 348 doit(omask); 349 /*NOTREACHED*/ 350} 351 352int child, defflags, deflflags, tabflag; 353char deferase, defkill; 354struct tchars deftc; 355struct ltchars defltc; 356struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 357struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 358 359void 360doit(omask) 361 long omask; 362{ 363 struct sgttyb sb; 364 365 (void)ioctl(0, TIOCGETP, (char *)&sb); 366 defflags = sb.sg_flags; 367 tabflag = defflags & TBDELAY; 368 defflags &= ECHO | CRMOD; 369 deferase = sb.sg_erase; 370 defkill = sb.sg_kill; 371 (void)ioctl(0, TIOCLGET, &deflflags); 372 (void)ioctl(0, TIOCGETC, &deftc); 373 notc.t_startc = deftc.t_startc; 374 notc.t_stopc = deftc.t_stopc; 375 (void)ioctl(0, TIOCGLTC, &defltc); 376 (void)signal(SIGINT, SIG_IGN); 377 setsignal(SIGHUP); 378 setsignal(SIGQUIT); 379 child = fork(); 380 if (child == -1) { 381 warn("fork"); 382 done(1); 383 } 384 if (child == 0) { 385 mode(1); 386 if (reader(omask) == 0) { 387 msg("connection closed."); 388 exit(0); 389 } 390 sleep(1); 391 msg("\007connection closed."); 392 exit(1); 393 } 394 395 /* 396 * We may still own the socket, and may have a pending SIGURG (or might 397 * receive one soon) that we really want to send to the reader. When 398 * one of these comes in, the trap copytochild simply copies such 399 * signals to the child. We can now unblock SIGURG and SIGUSR1 400 * that were set above. 401 */ 402 (void)sigsetmask(omask); 403 (void)signal(SIGCHLD, catch_child); 404 writer(); 405 msg("closed connection."); 406 done(0); 407} 408 409/* trap a signal, unless it is being ignored. */ 410void 411setsignal(sig) 412 int sig; 413{ 414 int omask = sigblock(sigmask(sig)); 415 416 if (signal(sig, exit) == SIG_IGN) 417 (void)signal(sig, SIG_IGN); 418 (void)sigsetmask(omask); 419} 420 421void 422done(status) 423 int status; 424{ 425 int w, wstatus; 426 427 mode(0); 428 if (child > 0) { 429 /* make sure catch_child does not snap it up */ 430 (void)signal(SIGCHLD, SIG_DFL); 431 if (kill(child, SIGKILL) >= 0) 432 while ((w = wait(&wstatus)) > 0 && w != child); 433 } 434 exit(status); 435} 436 437int dosigwinch; 438 439/* 440 * This is called when the reader process gets the out-of-band (urgent) 441 * request to turn on the window-changing protocol. 442 */ 443void 444writeroob(signo) 445 int signo; 446{ 447 if (dosigwinch == 0) { 448 sendwindow(); 449 (void)signal(SIGWINCH, sigwinch); 450 } 451 dosigwinch = 1; 452} 453 454void 455catch_child(signo) 456 int signo; 457{ 458 union wait status; 459 int pid; 460 461 for (;;) { 462 pid = wait3((int *)&status, WNOHANG|WUNTRACED, NULL); 463 if (pid == 0) 464 return; 465 /* if the child (reader) dies, just quit */ 466 if (pid < 0 || (pid == child && !WIFSTOPPED(status))) 467 done((int)(status.w_termsig | status.w_retcode)); 468 } 469 /* NOTREACHED */ 470} 471 472/* 473 * writer: write to remote: 0 -> line. 474 * ~. terminate 475 * ~^Z suspend rlogin process. 476 * ~<delayed-suspend char> suspend rlogin process, but leave reader alone. 477 */ 478void 479writer() 480{ 481 register int bol, local, n; 482 char c; 483 484 bol = 1; /* beginning of line */ 485 local = 0; 486 for (;;) { 487 n = read(STDIN_FILENO, &c, 1); 488 if (n <= 0) { 489 if (n < 0 && errno == EINTR) 490 continue; 491 break; 492 } 493 /* 494 * If we're at the beginning of the line and recognize a 495 * command character, then we echo locally. Otherwise, 496 * characters are echo'd remotely. If the command character 497 * is doubled, this acts as a force and local echo is 498 * suppressed. 499 */ 500 if (bol) { 501 bol = 0; 502 if (!noescape && c == escapechar) { 503 local = 1; 504 continue; 505 } 506 } else if (local) { 507 local = 0; 508 if (c == '.' || c == deftc.t_eofc) { 509 echo(c); 510 break; 511 } 512 if (c == defltc.t_suspc || c == defltc.t_dsuspc) { 513 bol = 1; 514 echo(c); 515 stop(c); 516 continue; 517 } 518 if (c != escapechar) 519#ifdef CRYPT 520#ifdef KERBEROS 521 if (doencrypt) 522 (void)des_enc_write(rem, 523 (char *)&escapechar, 1, 524 schedule, &cred.session); 525 else 526#endif 527#endif 528 (void)write(rem, &escapechar, 1); 529 } 530 531#ifdef CRYPT 532#ifdef KERBEROS 533 if (doencrypt) { 534 if (des_enc_write(rem, &c, 1, schedule, &cred.session) == 0) { 535 msg("line gone"); 536 break; 537 } 538 } else 539#endif 540#endif 541 if (write(rem, &c, 1) == 0) { 542 msg("line gone"); 543 break; 544 } 545 bol = c == defkill || c == deftc.t_eofc || 546 c == deftc.t_intrc || c == defltc.t_suspc || 547 c == '\r' || c == '\n'; 548 } 549} 550 551void 552#if __STDC__ 553echo(register char c) 554#else 555echo(c) 556 register char c; 557#endif 558{ 559 register char *p; 560 char buf[8]; 561 562 p = buf; 563 c &= 0177; 564 *p++ = escapechar; 565 if (c < ' ') { 566 *p++ = '^'; 567 *p++ = c + '@'; 568 } else if (c == 0177) { 569 *p++ = '^'; 570 *p++ = '?'; 571 } else 572 *p++ = c; 573 *p++ = '\r'; 574 *p++ = '\n'; 575 (void)write(STDOUT_FILENO, buf, p - buf); 576} 577 578void 579#if __STDC__ 580stop(char cmdc) 581#else 582stop(cmdc) 583 char cmdc; 584#endif 585{ 586 mode(0); 587 (void)signal(SIGCHLD, SIG_IGN); 588 (void)kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP); 589 (void)signal(SIGCHLD, catch_child); 590 mode(1); 591 sigwinch(0); /* check for size changes */ 592} 593 594void 595sigwinch(signo) 596 int signo; 597{ 598 struct winsize ws; 599 600 if (dosigwinch && get_window_size(0, &ws) == 0 && 601 bcmp(&ws, &winsize, sizeof(ws))) { 602 winsize = ws; 603 sendwindow(); 604 } 605} 606 607/* 608 * Send the window size to the server via the magic escape 609 */ 610void 611sendwindow() 612{ 613 struct winsize *wp; 614 char obuf[4 + sizeof (struct winsize)]; 615 616 wp = (struct winsize *)(obuf+4); 617 obuf[0] = 0377; 618 obuf[1] = 0377; 619 obuf[2] = 's'; 620 obuf[3] = 's'; 621 wp->ws_row = htons(winsize.ws_row); 622 wp->ws_col = htons(winsize.ws_col); 623 wp->ws_xpixel = htons(winsize.ws_xpixel); 624 wp->ws_ypixel = htons(winsize.ws_ypixel); 625 626#ifdef CRYPT 627#ifdef KERBEROS 628 if(doencrypt) 629 (void)des_enc_write(rem, obuf, sizeof(obuf), 630 schedule, &cred.session); 631 else 632#endif 633#endif 634 (void)write(rem, obuf, sizeof(obuf)); 635} 636 637/* 638 * reader: read from remote: line -> 1 639 */ 640#define READING 1 641#define WRITING 2 642 643jmp_buf rcvtop; 644int ppid, rcvcnt, rcvstate; 645char rcvbuf[8 * 1024]; 646 647void 648oob(signo) 649 int signo; 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 < 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(omask) 740 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 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(f) 794 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(signo) 836 int signo; 837{ 838 (void)signal(SIGPIPE, SIG_IGN); 839 msg("\007connection closed."); 840 done(1); 841} 842 843/* copy SIGURGs to the child process. */ 844void 845copytochild(signo) 846 int signo; 847{ 848 (void)kill(child, SIGURG); 849} 850 851void 852msg(str) 853 char *str; 854{ 855 (void)fprintf(stderr, "rlogin: %s\r\n", str); 856} 857 858void 859usage() 860{ 861 (void)fprintf(stderr, 862 "usage: rlogin [ -%s]%s[-e char] [ -l username ] host\n", 863#ifdef KERBEROS 864#ifdef CRYPT 865 "8DEKLx", " [-k realm] "); 866#else 867 "8DEKL", " [-k realm] "); 868#endif 869#else 870 "8DEL", " "); 871#endif 872 exit(1); 873} 874 875/* 876 * The following routine provides compatibility (such as it is) between older 877 * Suns and others. Suns have only a `ttysize', so we convert it to a winsize. 878 */ 879#ifdef OLDSUN 880int 881get_window_size(fd, wp) 882 int fd; 883 struct winsize *wp; 884{ 885 struct ttysize ts; 886 int error; 887 888 if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0) 889 return (error); 890 wp->ws_row = ts.ts_lines; 891 wp->ws_col = ts.ts_cols; 892 wp->ws_xpixel = 0; 893 wp->ws_ypixel = 0; 894 return (0); 895} 896#endif 897 898u_int 899getescape(p) 900 register char *p; 901{ 902 long val; 903 int len; 904 905 if ((len = strlen(p)) == 1) /* use any single char, including '\' */ 906 return ((u_int)*p); 907 /* otherwise, \nnn */ 908 if (*p == '\\' && len >= 2 && len <= 4) { 909 val = strtol(++p, NULL, 8); 910 for (;;) { 911 if (!*++p) 912 return ((u_int)val); 913 if (*p < '0' || *p > '8') 914 break; 915 } 916 } 917 msg("illegal option value -- e"); 918 usage(); 919 /* NOTREACHED */ 920} 921