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