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