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