|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1983 Regents of the University of California. ! 3: * All rights reserved. The Berkeley software License Agreement ! 4: * specifies the terms and conditions for redistribution. ! 5: */ ! 6: ! 7: #ifndef lint ! 8: char copyright[] = ! 9: "@(#) Copyright (c) 1983 Regents of the University of California.\n\ ! 10: All rights reserved.\n"; ! 11: #endif not lint ! 12: ! 13: #ifndef lint ! 14: static char sccsid[] = "@(#)rlogin.c 5.11 (Berkeley) 8/7/86"; ! 15: #endif not lint ! 16: ! 17: /* ! 18: * rlogin - remote login ! 19: */ ! 20: #include <sys/param.h> ! 21: #include <sys/errno.h> ! 22: #include <sys/file.h> ! 23: #include <sys/socket.h> ! 24: #include <sys/time.h> ! 25: #include <sys/resource.h> ! 26: #include <sys/wait.h> ! 27: ! 28: #include <netinet/in.h> ! 29: ! 30: #include <stdio.h> ! 31: #include <sgtty.h> ! 32: #include <errno.h> ! 33: #include <pwd.h> ! 34: #include <signal.h> ! 35: #include <setjmp.h> ! 36: #include <netdb.h> ! 37: ! 38: # ifndef TIOCPKT_WINDOW ! 39: # define TIOCPKT_WINDOW 0x80 ! 40: # endif TIOCPKT_WINDOW ! 41: ! 42: /* concession to sun */ ! 43: # ifndef SIGUSR1 ! 44: # define SIGUSR1 30 ! 45: # endif SIGUSR1 ! 46: ! 47: char *index(), *rindex(), *malloc(), *getenv(), *strcat(), *strcpy(); ! 48: struct passwd *getpwuid(); ! 49: char *name; ! 50: int rem; ! 51: char cmdchar = '~'; ! 52: int eight; ! 53: int litout; ! 54: char *speeds[] = ! 55: { "0", "50", "75", "110", "134", "150", "200", "300", ! 56: "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" }; ! 57: char term[256] = "network"; ! 58: extern int errno; ! 59: int lostpeer(); ! 60: int dosigwinch = 0; ! 61: #ifndef sigmask ! 62: #define sigmask(m) (1 << ((m)-1)) ! 63: #endif ! 64: #ifdef sun ! 65: struct winsize { ! 66: unsigned short ws_row, ws_col; ! 67: unsigned short ws_xpixel, ws_ypixel; ! 68: }; ! 69: #endif sun ! 70: struct winsize winsize; ! 71: int sigwinch(), oob(); ! 72: ! 73: /* ! 74: * The following routine provides compatibility (such as it is) ! 75: * between 4.2BSD Suns and others. Suns have only a `ttysize', ! 76: * so we convert it to a winsize. ! 77: */ ! 78: #ifdef sun ! 79: int ! 80: get_window_size(fd, wp) ! 81: int fd; ! 82: struct winsize *wp; ! 83: { ! 84: struct ttysize ts; ! 85: int error; ! 86: ! 87: if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0) ! 88: return (error); ! 89: wp->ws_row = ts.ts_lines; ! 90: wp->ws_col = ts.ts_cols; ! 91: wp->ws_xpixel = 0; ! 92: wp->ws_ypixel = 0; ! 93: return (0); ! 94: } ! 95: #else sun ! 96: #define get_window_size(fd, wp) ioctl(fd, TIOCGWINSZ, wp) ! 97: #endif sun ! 98: ! 99: main(argc, argv) ! 100: int argc; ! 101: char **argv; ! 102: { ! 103: char *host, *cp; ! 104: struct sgttyb ttyb; ! 105: struct passwd *pwd; ! 106: struct servent *sp; ! 107: int uid, options = 0, oldmask; ! 108: int on = 1; ! 109: ! 110: host = rindex(argv[0], '/'); ! 111: if (host) ! 112: host++; ! 113: else ! 114: host = argv[0]; ! 115: argv++, --argc; ! 116: if (!strcmp(host, "rlogin")) ! 117: host = *argv++, --argc; ! 118: another: ! 119: if (argc > 0 && !strcmp(*argv, "-d")) { ! 120: argv++, argc--; ! 121: options |= SO_DEBUG; ! 122: goto another; ! 123: } ! 124: if (argc > 0 && !strcmp(*argv, "-l")) { ! 125: argv++, argc--; ! 126: if (argc == 0) ! 127: goto usage; ! 128: name = *argv++; argc--; ! 129: goto another; ! 130: } ! 131: if (argc > 0 && !strncmp(*argv, "-e", 2)) { ! 132: cmdchar = argv[0][2]; ! 133: argv++, argc--; ! 134: goto another; ! 135: } ! 136: if (argc > 0 && !strcmp(*argv, "-8")) { ! 137: eight = 1; ! 138: argv++, argc--; ! 139: goto another; ! 140: } ! 141: if (argc > 0 && !strcmp(*argv, "-L")) { ! 142: litout = 1; ! 143: argv++, argc--; ! 144: goto another; ! 145: } ! 146: if (host == 0) ! 147: goto usage; ! 148: if (argc > 0) ! 149: goto usage; ! 150: pwd = getpwuid(getuid()); ! 151: if (pwd == 0) { ! 152: fprintf(stderr, "Who are you?\n"); ! 153: exit(1); ! 154: } ! 155: sp = getservbyname("login", "tcp"); ! 156: if (sp == 0) { ! 157: fprintf(stderr, "rlogin: login/tcp: unknown service\n"); ! 158: exit(2); ! 159: } ! 160: cp = getenv("TERM"); ! 161: if (cp) ! 162: (void) strcpy(term, cp); ! 163: if (ioctl(0, TIOCGETP, &ttyb) == 0) { ! 164: (void) strcat(term, "/"); ! 165: (void) strcat(term, speeds[ttyb.sg_ospeed]); ! 166: } ! 167: (void) get_window_size(0, &winsize); ! 168: (void) signal(SIGPIPE, lostpeer); ! 169: /* will use SIGUSR1 for window size hack, so hold it off */ ! 170: oldmask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1)); ! 171: rem = rcmd(&host, sp->s_port, pwd->pw_name, ! 172: name ? name : pwd->pw_name, term, 0); ! 173: if (rem < 0) ! 174: exit(1); ! 175: if (options & SO_DEBUG && ! 176: setsockopt(rem, SOL_SOCKET, SO_DEBUG, &on, sizeof (on)) < 0) ! 177: perror("rlogin: setsockopt (SO_DEBUG)"); ! 178: uid = getuid(); ! 179: if (setuid(uid) < 0) { ! 180: perror("rlogin: setuid"); ! 181: exit(1); ! 182: } ! 183: doit(oldmask); ! 184: /*NOTREACHED*/ ! 185: usage: ! 186: fprintf(stderr, ! 187: "usage: rlogin host [ -ex ] [ -l username ] [ -8 ] [ -L ]\n"); ! 188: exit(1); ! 189: } ! 190: ! 191: #define CRLF "\r\n" ! 192: ! 193: int child; ! 194: int catchild(); ! 195: int copytochild(), writeroob(); ! 196: ! 197: int defflags, tabflag; ! 198: int deflflags; ! 199: char deferase, defkill; ! 200: struct tchars deftc; ! 201: struct ltchars defltc; ! 202: struct tchars notc = { -1, -1, -1, -1, -1, -1 }; ! 203: struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; ! 204: ! 205: doit(oldmask) ! 206: { ! 207: int exit(); ! 208: struct sgttyb sb; ! 209: ! 210: (void) ioctl(0, TIOCGETP, (char *)&sb); ! 211: defflags = sb.sg_flags; ! 212: tabflag = defflags & TBDELAY; ! 213: defflags &= ECHO | CRMOD; ! 214: deferase = sb.sg_erase; ! 215: defkill = sb.sg_kill; ! 216: (void) ioctl(0, TIOCLGET, (char *)&deflflags); ! 217: (void) ioctl(0, TIOCGETC, (char *)&deftc); ! 218: notc.t_startc = deftc.t_startc; ! 219: notc.t_stopc = deftc.t_stopc; ! 220: (void) ioctl(0, TIOCGLTC, (char *)&defltc); ! 221: (void) signal(SIGINT, SIG_IGN); ! 222: setsignal(SIGHUP, exit); ! 223: setsignal(SIGQUIT, exit); ! 224: child = fork(); ! 225: if (child == -1) { ! 226: perror("rlogin: fork"); ! 227: done(1); ! 228: } ! 229: if (child == 0) { ! 230: mode(1); ! 231: if (reader(oldmask) == 0) { ! 232: prf("Connection closed."); ! 233: exit(0); ! 234: } ! 235: sleep(1); ! 236: prf("\007Connection closed."); ! 237: exit(3); ! 238: } ! 239: ! 240: /* ! 241: * We may still own the socket, and may have a pending SIGURG ! 242: * (or might receive one soon) that we really want to send to ! 243: * the reader. Set a trap that simply copies such signals to ! 244: * the child. ! 245: */ ! 246: (void) signal(SIGURG, copytochild); ! 247: (void) signal(SIGUSR1, writeroob); ! 248: (void) sigsetmask(oldmask); ! 249: (void) signal(SIGCHLD, catchild); ! 250: writer(); ! 251: prf("Closed connection."); ! 252: done(0); ! 253: } ! 254: ! 255: /* ! 256: * Trap a signal, unless it is being ignored. ! 257: */ ! 258: setsignal(sig, act) ! 259: int sig, (*act)(); ! 260: { ! 261: int omask = sigblock(sigmask(sig)); ! 262: ! 263: if (signal(sig, act) == SIG_IGN) ! 264: (void) signal(sig, SIG_IGN); ! 265: (void) sigsetmask(omask); ! 266: } ! 267: ! 268: done(status) ! 269: int status; ! 270: { ! 271: int w; ! 272: ! 273: mode(0); ! 274: if (child > 0) { ! 275: /* make sure catchild does not snap it up */ ! 276: (void) signal(SIGCHLD, SIG_DFL); ! 277: if (kill(child, SIGKILL) >= 0) ! 278: while ((w = wait((union wait *)0)) > 0 && w != child) ! 279: /*void*/; ! 280: } ! 281: exit(status); ! 282: } ! 283: ! 284: /* ! 285: * Copy SIGURGs to the child process. ! 286: */ ! 287: copytochild() ! 288: { ! 289: ! 290: (void) kill(child, SIGURG); ! 291: } ! 292: ! 293: /* ! 294: * This is called when the reader process gets the out-of-band (urgent) ! 295: * request to turn on the window-changing protocol. ! 296: */ ! 297: writeroob() ! 298: { ! 299: ! 300: if (dosigwinch == 0) { ! 301: sendwindow(); ! 302: (void) signal(SIGWINCH, sigwinch); ! 303: } ! 304: dosigwinch = 1; ! 305: } ! 306: ! 307: catchild() ! 308: { ! 309: union wait status; ! 310: int pid; ! 311: ! 312: again: ! 313: pid = wait3(&status, WNOHANG|WUNTRACED, (struct rusage *)0); ! 314: if (pid == 0) ! 315: return; ! 316: /* ! 317: * if the child (reader) dies, just quit ! 318: */ ! 319: if (pid < 0 || pid == child && !WIFSTOPPED(status)) ! 320: done((int)(status.w_termsig | status.w_retcode)); ! 321: goto again; ! 322: } ! 323: ! 324: /* ! 325: * writer: write to remote: 0 -> line. ! 326: * ~. terminate ! 327: * ~^Z suspend rlogin process. ! 328: * ~^Y suspend rlogin process, but leave reader alone. ! 329: */ ! 330: writer() ! 331: { ! 332: char c; ! 333: register n; ! 334: register bol = 1; /* beginning of line */ ! 335: register local = 0; ! 336: ! 337: for (;;) { ! 338: n = read(0, &c, 1); ! 339: if (n <= 0) { ! 340: if (n < 0 && errno == EINTR) ! 341: continue; ! 342: break; ! 343: } ! 344: /* ! 345: * If we're at the beginning of the line ! 346: * and recognize a command character, then ! 347: * we echo locally. Otherwise, characters ! 348: * are echo'd remotely. If the command ! 349: * character is doubled, this acts as a ! 350: * force and local echo is suppressed. ! 351: */ ! 352: if (bol) { ! 353: bol = 0; ! 354: if (c == cmdchar) { ! 355: bol = 0; ! 356: local = 1; ! 357: continue; ! 358: } ! 359: } else if (local) { ! 360: local = 0; ! 361: if (c == '.' || c == deftc.t_eofc) { ! 362: echo(c); ! 363: break; ! 364: } ! 365: if (c == defltc.t_suspc || c == defltc.t_dsuspc) { ! 366: bol = 1; ! 367: echo(c); ! 368: stop(c); ! 369: continue; ! 370: } ! 371: if (c != cmdchar) ! 372: (void) write(rem, &cmdchar, 1); ! 373: } ! 374: if (write(rem, &c, 1) == 0) { ! 375: prf("line gone"); ! 376: break; ! 377: } ! 378: bol = c == defkill || c == deftc.t_eofc || ! 379: c == deftc.t_intrc || c == defltc.t_suspc || ! 380: c == '\r' || c == '\n'; ! 381: } ! 382: } ! 383: ! 384: echo(c) ! 385: register char c; ! 386: { ! 387: char buf[8]; ! 388: register char *p = buf; ! 389: ! 390: c &= 0177; ! 391: *p++ = cmdchar; ! 392: if (c < ' ') { ! 393: *p++ = '^'; ! 394: *p++ = c + '@'; ! 395: } else if (c == 0177) { ! 396: *p++ = '^'; ! 397: *p++ = '?'; ! 398: } else ! 399: *p++ = c; ! 400: *p++ = '\r'; ! 401: *p++ = '\n'; ! 402: (void) write(1, buf, p - buf); ! 403: } ! 404: ! 405: stop(cmdc) ! 406: char cmdc; ! 407: { ! 408: mode(0); ! 409: (void) signal(SIGCHLD, SIG_IGN); ! 410: (void) kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP); ! 411: (void) signal(SIGCHLD, catchild); ! 412: mode(1); ! 413: sigwinch(); /* check for size changes */ ! 414: } ! 415: ! 416: sigwinch() ! 417: { ! 418: struct winsize ws; ! 419: ! 420: if (dosigwinch && get_window_size(0, &ws) == 0 && ! 421: bcmp(&ws, &winsize, sizeof (ws))) { ! 422: winsize = ws; ! 423: sendwindow(); ! 424: } ! 425: } ! 426: ! 427: /* ! 428: * Send the window size to the server via the magic escape ! 429: */ ! 430: sendwindow() ! 431: { ! 432: char obuf[4 + sizeof (struct winsize)]; ! 433: struct winsize *wp = (struct winsize *)(obuf+4); ! 434: ! 435: obuf[0] = 0377; ! 436: obuf[1] = 0377; ! 437: obuf[2] = 's'; ! 438: obuf[3] = 's'; ! 439: wp->ws_row = htons(winsize.ws_row); ! 440: wp->ws_col = htons(winsize.ws_col); ! 441: wp->ws_xpixel = htons(winsize.ws_xpixel); ! 442: wp->ws_ypixel = htons(winsize.ws_ypixel); ! 443: (void) write(rem, obuf, sizeof(obuf)); ! 444: } ! 445: ! 446: /* ! 447: * reader: read from remote: line -> 1 ! 448: */ ! 449: #define READING 1 ! 450: #define WRITING 2 ! 451: ! 452: char rcvbuf[8 * 1024]; ! 453: int rcvcnt; ! 454: int rcvstate; ! 455: int ppid; ! 456: jmp_buf rcvtop; ! 457: ! 458: oob() ! 459: { ! 460: int out = FWRITE, atmark, n; ! 461: int rcvd = 0; ! 462: char waste[BUFSIZ], mark; ! 463: struct sgttyb sb; ! 464: ! 465: while (recv(rem, &mark, 1, MSG_OOB) < 0) ! 466: switch (errno) { ! 467: ! 468: case EWOULDBLOCK: ! 469: /* ! 470: * Urgent data not here yet. ! 471: * It may not be possible to send it yet ! 472: * if we are blocked for output ! 473: * and our input buffer is full. ! 474: */ ! 475: if (rcvcnt < sizeof(rcvbuf)) { ! 476: n = read(rem, rcvbuf + rcvcnt, ! 477: sizeof(rcvbuf) - rcvcnt); ! 478: if (n <= 0) ! 479: return; ! 480: rcvd += n; ! 481: } else { ! 482: n = read(rem, waste, sizeof(waste)); ! 483: if (n <= 0) ! 484: return; ! 485: } ! 486: continue; ! 487: ! 488: default: ! 489: return; ! 490: } ! 491: if (mark & TIOCPKT_WINDOW) { ! 492: /* ! 493: * Let server know about window size changes ! 494: */ ! 495: (void) kill(ppid, SIGUSR1); ! 496: } ! 497: if (!eight && (mark & TIOCPKT_NOSTOP)) { ! 498: (void) ioctl(0, TIOCGETP, (char *)&sb); ! 499: sb.sg_flags &= ~CBREAK; ! 500: sb.sg_flags |= RAW; ! 501: (void) ioctl(0, TIOCSETN, (char *)&sb); ! 502: notc.t_stopc = -1; ! 503: notc.t_startc = -1; ! 504: (void) ioctl(0, TIOCSETC, (char *)¬c); ! 505: } ! 506: if (!eight && (mark & TIOCPKT_DOSTOP)) { ! 507: (void) ioctl(0, TIOCGETP, (char *)&sb); ! 508: sb.sg_flags &= ~RAW; ! 509: sb.sg_flags |= CBREAK; ! 510: (void) ioctl(0, TIOCSETN, (char *)&sb); ! 511: notc.t_stopc = deftc.t_stopc; ! 512: notc.t_startc = deftc.t_startc; ! 513: (void) ioctl(0, TIOCSETC, (char *)¬c); ! 514: } ! 515: if (mark & TIOCPKT_FLUSHWRITE) { ! 516: (void) ioctl(1, TIOCFLUSH, (char *)&out); ! 517: for (;;) { ! 518: if (ioctl(rem, SIOCATMARK, &atmark) < 0) { ! 519: perror("ioctl"); ! 520: break; ! 521: } ! 522: if (atmark) ! 523: break; ! 524: n = read(rem, waste, sizeof (waste)); ! 525: if (n <= 0) ! 526: break; ! 527: } ! 528: /* ! 529: * Don't want any pending data to be output, ! 530: * so clear the recv buffer. ! 531: * If we were hanging on a write when interrupted, ! 532: * don't want it to restart. If we were reading, ! 533: * restart anyway. ! 534: */ ! 535: rcvcnt = 0; ! 536: longjmp(rcvtop, 1); ! 537: } ! 538: ! 539: /* ! 540: * oob does not do FLUSHREAD (alas!) ! 541: */ ! 542: ! 543: /* ! 544: * If we filled the receive buffer while a read was pending, ! 545: * longjmp to the top to restart appropriately. Don't abort ! 546: * a pending write, however, or we won't know how much was written. ! 547: */ ! 548: if (rcvd && rcvstate == READING) ! 549: longjmp(rcvtop, 1); ! 550: } ! 551: ! 552: /* ! 553: * reader: read from remote: line -> 1 ! 554: */ ! 555: reader(oldmask) ! 556: int oldmask; ! 557: { ! 558: #if !defined(BSD) || BSD < 43 ! 559: int pid = -getpid(); ! 560: #else ! 561: int pid = getpid(); ! 562: #endif ! 563: int n, remaining; ! 564: char *bufp = rcvbuf; ! 565: ! 566: (void) signal(SIGTTOU, SIG_IGN); ! 567: (void) signal(SIGURG, oob); ! 568: ppid = getppid(); ! 569: (void) fcntl(rem, F_SETOWN, pid); ! 570: (void) setjmp(rcvtop); ! 571: (void) sigsetmask(oldmask); ! 572: for (;;) { ! 573: while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) { ! 574: rcvstate = WRITING; ! 575: n = write(1, bufp, remaining); ! 576: if (n < 0) { ! 577: if (errno != EINTR) ! 578: return (-1); ! 579: continue; ! 580: } ! 581: bufp += n; ! 582: } ! 583: bufp = rcvbuf; ! 584: rcvcnt = 0; ! 585: rcvstate = READING; ! 586: rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf)); ! 587: if (rcvcnt == 0) ! 588: return (0); ! 589: if (rcvcnt < 0) { ! 590: if (errno == EINTR) ! 591: continue; ! 592: perror("read"); ! 593: return (-1); ! 594: } ! 595: } ! 596: } ! 597: ! 598: mode(f) ! 599: { ! 600: struct tchars *tc; ! 601: struct ltchars *ltc; ! 602: struct sgttyb sb; ! 603: int lflags; ! 604: ! 605: (void) ioctl(0, TIOCGETP, (char *)&sb); ! 606: (void) ioctl(0, TIOCLGET, (char *)&lflags); ! 607: switch (f) { ! 608: ! 609: case 0: ! 610: sb.sg_flags &= ~(CBREAK|RAW|TBDELAY); ! 611: sb.sg_flags |= defflags|tabflag; ! 612: tc = &deftc; ! 613: ltc = &defltc; ! 614: sb.sg_kill = defkill; ! 615: sb.sg_erase = deferase; ! 616: lflags = deflflags; ! 617: break; ! 618: ! 619: case 1: ! 620: sb.sg_flags |= (eight ? RAW : CBREAK); ! 621: sb.sg_flags &= ~defflags; ! 622: /* preserve tab delays, but turn off XTABS */ ! 623: if ((sb.sg_flags & TBDELAY) == XTABS) ! 624: sb.sg_flags &= ~TBDELAY; ! 625: tc = ¬c; ! 626: ltc = &noltc; ! 627: sb.sg_kill = sb.sg_erase = -1; ! 628: if (litout) ! 629: lflags |= LLITOUT; ! 630: break; ! 631: ! 632: default: ! 633: return; ! 634: } ! 635: (void) ioctl(0, TIOCSLTC, (char *)ltc); ! 636: (void) ioctl(0, TIOCSETC, (char *)tc); ! 637: (void) ioctl(0, TIOCSETN, (char *)&sb); ! 638: (void) ioctl(0, TIOCLSET, (char *)&lflags); ! 639: } ! 640: ! 641: /*VARARGS*/ ! 642: prf(f, a1, a2, a3, a4, a5) ! 643: char *f; ! 644: { ! 645: ! 646: fprintf(stderr, f, a1, a2, a3, a4, a5); ! 647: fprintf(stderr, CRLF); ! 648: } ! 649: ! 650: lostpeer() ! 651: { ! 652: ! 653: (void) signal(SIGPIPE, SIG_IGN); ! 654: prf("\007Connection closed."); ! 655: done(1); ! 656: } ! 657:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.