Annotation of 43BSDTahoe/ucb/rlogin.c, revision 1.1.1.1

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 *)&notc);
                    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 *)&notc);
                    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 = &notc;
                    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: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.