Annotation of 43BSD/etc/telnetd.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1983,1986 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[] = "@(#)telnetd.c  5.18 (Berkeley) 5/12/86";
                     15: #endif not lint
                     16: 
                     17: /*
                     18:  * Telnet server.
                     19:  */
                     20: #include <sys/param.h>
                     21: #include <sys/socket.h>
                     22: #include <sys/wait.h>
                     23: #include <sys/file.h>
                     24: #include <sys/stat.h>
                     25: #include <sys/time.h>
                     26: 
                     27: #include <netinet/in.h>
                     28: 
                     29: #include <arpa/telnet.h>
                     30: 
                     31: #include <stdio.h>
                     32: #include <signal.h>
                     33: #include <errno.h>
                     34: #include <sgtty.h>
                     35: #include <netdb.h>
                     36: #include <syslog.h>
                     37: #include <ctype.h>
                     38: 
                     39: #define        OPT_NO                  0               /* won't do this option */
                     40: #define        OPT_YES                 1               /* will do this option */
                     41: #define        OPT_YES_BUT_ALWAYS_LOOK 2
                     42: #define        OPT_NO_BUT_ALWAYS_LOOK  3
                     43: char   hisopts[256];
                     44: char   myopts[256];
                     45: 
                     46: char   doopt[] = { IAC, DO, '%', 'c', 0 };
                     47: char   dont[] = { IAC, DONT, '%', 'c', 0 };
                     48: char   will[] = { IAC, WILL, '%', 'c', 0 };
                     49: char   wont[] = { IAC, WONT, '%', 'c', 0 };
                     50: 
                     51: /*
                     52:  * I/O data buffers, pointers, and counters.
                     53:  */
                     54: char   ptyibuf[BUFSIZ], *ptyip = ptyibuf;
                     55: 
                     56: char   ptyobuf[BUFSIZ], *pfrontp = ptyobuf, *pbackp = ptyobuf;
                     57: 
                     58: char   netibuf[BUFSIZ], *netip = netibuf;
                     59: #define        NIACCUM(c)      {   *netip++ = c; \
                     60:                            ncc++; \
                     61:                        }
                     62: 
                     63: char   netobuf[BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf;
                     64: char   *neturg = 0;            /* one past last bye of urgent data */
                     65:        /* the remote system seems to NOT be an old 4.2 */
                     66: int    not42 = 1;
                     67: 
                     68: 
                     69: char BANNER1[] = "\r\n\r\n4.3 BSD UNIX (",
                     70:     BANNER2[] = ")\r\n\r\0\r\n\r\0";
                     71: 
                     72:                /* buffer for sub-options */
                     73: char   subbuffer[100], *subpointer= subbuffer, *subend= subbuffer;
                     74: #define        SB_CLEAR()      subpointer = subbuffer;
                     75: #define        SB_TERM()       { subend = subpointer; SB_CLEAR(); }
                     76: #define        SB_ACCUM(c)     if (subpointer < (subbuffer+sizeof subbuffer)) { \
                     77:                                *subpointer++ = (c); \
                     78:                        }
                     79: #define        SB_GET()        ((*subpointer++)&0xff)
                     80: #define        SB_EOF()        (subpointer >= subend)
                     81: 
                     82: int    pcc, ncc;
                     83: 
                     84: int    pty, net;
                     85: int    inter;
                     86: extern char **environ;
                     87: extern int errno;
                     88: char   *line;
                     89: int    SYNCHing = 0;           /* we are in TELNET SYNCH mode */
                     90: /*
                     91:  * The following are some clocks used to decide how to interpret
                     92:  * the relationship between various variables.
                     93:  */
                     94: 
                     95: struct {
                     96:     int
                     97:        system,                 /* what the current time is */
                     98:        echotoggle,             /* last time user entered echo character */
                     99:        modenegotiated,         /* last time operating mode negotiated */
                    100:        didnetreceive,          /* last time we read data from network */
                    101:        ttypeopt,               /* ttype will/won't received */
                    102:        ttypesubopt,            /* ttype subopt is received */
                    103:        getterminal,            /* time started to get terminal information */
                    104:        gotDM;                  /* when did we last see a data mark */
                    105: } clocks;
                    106: 
                    107: #define        settimer(x)     (clocks.x = ++clocks.system)
                    108: #define        sequenceIs(x,y) (clocks.x < clocks.y)
                    109: 
                    110: main(argc, argv)
                    111:        char *argv[];
                    112: {
                    113:        struct sockaddr_in from;
                    114:        int on = 1, fromlen;
                    115: 
                    116: #if    defined(DEBUG)
                    117:        {
                    118:            int s, ns, foo;
                    119:            struct servent *sp;
                    120:            static struct sockaddr_in sin = { AF_INET };
                    121: 
                    122:            sp = getservbyname("telnet", "tcp");
                    123:            if (sp == 0) {
                    124:                    fprintf(stderr, "telnetd: tcp/telnet: unknown service\n");
                    125:                    exit(1);
                    126:            }
                    127:            sin.sin_port = sp->s_port;
                    128:            argc--, argv++;
                    129:            if (argc > 0) {
                    130:                    sin.sin_port = atoi(*argv);
                    131:                    sin.sin_port = htons((u_short)sin.sin_port);
                    132:            }
                    133: 
                    134:            s = socket(AF_INET, SOCK_STREAM, 0);
                    135:            if (s < 0) {
                    136:                    perror("telnetd: socket");;
                    137:                    exit(1);
                    138:            }
                    139:            if (bind(s, &sin, sizeof sin) < 0) {
                    140:                perror("bind");
                    141:                exit(1);
                    142:            }
                    143:            if (listen(s, 1) < 0) {
                    144:                perror("listen");
                    145:                exit(1);
                    146:            }
                    147:            foo = sizeof sin;
                    148:            ns = accept(s, &sin, &foo);
                    149:            if (ns < 0) {
                    150:                perror("accept");
                    151:                exit(1);
                    152:            }
                    153:            dup2(ns, 0);
                    154:            close(s);
                    155:        }
                    156: #endif /* defined(DEBUG) */
                    157:        openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
                    158:        fromlen = sizeof (from);
                    159:        if (getpeername(0, &from, &fromlen) < 0) {
                    160:                fprintf(stderr, "%s: ", argv[0]);
                    161:                perror("getpeername");
                    162:                _exit(1);
                    163:        }
                    164:        if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) {
                    165:                syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
                    166:        }
                    167:        doit(0, &from);
                    168: }
                    169: 
                    170: char   *terminaltype = 0;
                    171: char   *envinit[2];
                    172: int    cleanup();
                    173: 
                    174: /*
                    175:  * ttloop
                    176:  *
                    177:  *     A small subroutine to flush the network output buffer, get some data
                    178:  * from the network, and pass it through the telnet state machine.  We
                    179:  * also flush the pty input buffer (by dropping its data) if it becomes
                    180:  * too full.
                    181:  */
                    182: 
                    183: void
                    184: ttloop()
                    185: {
                    186:     if (nfrontp-nbackp) {
                    187:        netflush();
                    188:     }
                    189:     ncc = read(net, netibuf, sizeof netibuf);
                    190:     if (ncc < 0) {
                    191:        syslog(LOG_INFO, "ttloop:  read: %m\n");
                    192:        exit(1);
                    193:     } else if (ncc == 0) {
                    194:        syslog(LOG_INFO, "ttloop:  peer died: %m\n");
                    195:        exit(1);
                    196:     }
                    197:     netip = netibuf;
                    198:     telrcv();                  /* state machine */
                    199:     if (ncc > 0) {
                    200:        pfrontp = pbackp = ptyobuf;
                    201:        telrcv();
                    202:     }
                    203: }
                    204: 
                    205: /*
                    206:  * getterminaltype
                    207:  *
                    208:  *     Ask the other end to send along its terminal type.
                    209:  * Output is the variable terminaltype filled in.
                    210:  */
                    211: 
                    212: void
                    213: getterminaltype()
                    214: {
                    215:     static char sbuf[] = { IAC, DO, TELOPT_TTYPE };
                    216: 
                    217:     settimer(getterminal);
                    218:     bcopy(sbuf, nfrontp, sizeof sbuf);
                    219:     nfrontp += sizeof sbuf;
                    220:     hisopts[TELOPT_TTYPE] = OPT_YES_BUT_ALWAYS_LOOK;
                    221:     while (sequenceIs(ttypeopt, getterminal)) {
                    222:        ttloop();
                    223:     }
                    224:     if (hisopts[TELOPT_TTYPE] == OPT_YES) {
                    225:        static char sbbuf[] = { IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE };
                    226: 
                    227:        bcopy(sbbuf, nfrontp, sizeof sbbuf);
                    228:        nfrontp += sizeof sbbuf;
                    229:        while (sequenceIs(ttypesubopt, getterminal)) {
                    230:            ttloop();
                    231:        }
                    232:     }
                    233: }
                    234: 
                    235: /*
                    236:  * Get a pty, scan input lines.
                    237:  */
                    238: doit(f, who)
                    239:        int f;
                    240:        struct sockaddr_in *who;
                    241: {
                    242:        char *host, *inet_ntoa();
                    243:        int i, p, t;
                    244:        struct sgttyb b;
                    245:        struct hostent *hp;
                    246:        int c;
                    247: 
                    248:        for (c = 'p'; c <= 's'; c++) {
                    249:                struct stat stb;
                    250: 
                    251:                line = "/dev/ptyXX";
                    252:                line[strlen("/dev/pty")] = c;
                    253:                line[strlen("/dev/ptyp")] = '0';
                    254:                if (stat(line, &stb) < 0)
                    255:                        break;
                    256:                for (i = 0; i < 16; i++) {
                    257:                        line[strlen("/dev/ptyp")] = "0123456789abcdef"[i];
                    258:                        p = open(line, 2);
                    259:                        if (p > 0)
                    260:                                goto gotpty;
                    261:                }
                    262:        }
                    263:        fatal(f, "All network ports in use");
                    264:        /*NOTREACHED*/
                    265: gotpty:
                    266:        dup2(f, 0);
                    267:        line[strlen("/dev/")] = 't';
                    268:        t = open("/dev/tty", O_RDWR);
                    269:        if (t >= 0) {
                    270:                ioctl(t, TIOCNOTTY, 0);
                    271:                close(t);
                    272:        }
                    273:        t = open(line, O_RDWR);
                    274:        if (t < 0)
                    275:                fatalperror(f, line, errno);
                    276:        ioctl(t, TIOCGETP, &b);
                    277:        b.sg_flags = CRMOD|XTABS|ANYP;
                    278:        ioctl(t, TIOCSETP, &b);
                    279:        ioctl(p, TIOCGETP, &b);
                    280:        b.sg_flags &= ~ECHO;
                    281:        ioctl(p, TIOCSETP, &b);
                    282:        hp = gethostbyaddr(&who->sin_addr, sizeof (struct in_addr),
                    283:                who->sin_family);
                    284:        if (hp)
                    285:                host = hp->h_name;
                    286:        else
                    287:                host = inet_ntoa(who->sin_addr);
                    288: 
                    289:        net = f;
                    290:        pty = p;
                    291: 
                    292:        /*
                    293:         * get terminal type.
                    294:         */
                    295:        getterminaltype();
                    296: 
                    297:        if ((i = fork()) < 0)
                    298:                fatalperror(f, "fork", errno);
                    299:        if (i)
                    300:                telnet(f, p);
                    301:        close(f);
                    302:        close(p);
                    303:        dup2(t, 0);
                    304:        dup2(t, 1);
                    305:        dup2(t, 2);
                    306:        close(t);
                    307:        envinit[0] = terminaltype;
                    308:        envinit[1] = 0;
                    309:        environ = envinit;
                    310:        /*
                    311:         * -h : pass on name of host.
                    312:         *              WARNING:  -h is accepted by login if and only if
                    313:         *                      getuid() == 0.
                    314:         * -p : don't clobber the environment (so terminal type stays set).
                    315:         */
                    316:        execl("/bin/login", "login", "-h", host,
                    317:                                        terminaltype ? "-p" : 0, 0);
                    318:        fatalperror(f, "/bin/login", errno);
                    319:        /*NOTREACHED*/
                    320: }
                    321: 
                    322: fatal(f, msg)
                    323:        int f;
                    324:        char *msg;
                    325: {
                    326:        char buf[BUFSIZ];
                    327: 
                    328:        (void) sprintf(buf, "telnetd: %s.\r\n", msg);
                    329:        (void) write(f, buf, strlen(buf));
                    330:        exit(1);
                    331: }
                    332: 
                    333: fatalperror(f, msg, errno)
                    334:        int f;
                    335:        char *msg;
                    336:        int errno;
                    337: {
                    338:        char buf[BUFSIZ];
                    339:        extern char *sys_errlist[];
                    340: 
                    341:        (void) sprintf(buf, "%s: %s\r\n", msg, sys_errlist[errno]);
                    342:        fatal(f, buf);
                    343: }
                    344: 
                    345: 
                    346: /*
                    347:  * Check a descriptor to see if out of band data exists on it.
                    348:  */
                    349: 
                    350: 
                    351: stilloob(s)
                    352: int    s;              /* socket number */
                    353: {
                    354:     static struct timeval timeout = { 0 };
                    355:     fd_set     excepts;
                    356:     int value;
                    357: 
                    358:     do {
                    359:        FD_ZERO(&excepts);
                    360:        FD_SET(s, &excepts);
                    361:        value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);
                    362:     } while ((value == -1) && (errno == EINTR));
                    363: 
                    364:     if (value < 0) {
                    365:        fatalperror(pty, "select", errno);
                    366:     }
                    367:     if (FD_ISSET(s, &excepts)) {
                    368:        return 1;
                    369:     } else {
                    370:        return 0;
                    371:     }
                    372: }
                    373: 
                    374: /*
                    375:  * Main loop.  Select from pty and network, and
                    376:  * hand data to telnet receiver finite state machine.
                    377:  */
                    378: telnet(f, p)
                    379: {
                    380:        int on = 1;
                    381:        char hostname[MAXHOSTNAMELEN];
                    382: 
                    383:        ioctl(f, FIONBIO, &on);
                    384:        ioctl(p, FIONBIO, &on);
                    385: #if    defined(SO_OOBINLINE)
                    386:        setsockopt(net, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
                    387: #endif /* defined(SO_OOBINLINE) */
                    388:        signal(SIGTSTP, SIG_IGN);
                    389:        signal(SIGCHLD, cleanup);
                    390:        setpgrp(0, 0);
                    391: 
                    392:        /*
                    393:         * Request to do remote echo and to suppress go ahead.
                    394:         */
                    395:        if (!myopts[TELOPT_ECHO]) {
                    396:            dooption(TELOPT_ECHO);
                    397:        }
                    398:        if (!myopts[TELOPT_SGA]) {
                    399:            dooption(TELOPT_SGA);
                    400:        }
                    401:        /*
                    402:         * Is the client side a 4.2 (NOT 4.3) system?  We need to know this
                    403:         * because 4.2 clients are unable to deal with TCP urgent data.
                    404:         *
                    405:         * To find out, we send out a "DO ECHO".  If the remote system
                    406:         * answers "WILL ECHO" it is probably a 4.2 client, and we note
                    407:         * that fact ("WILL ECHO" ==> that the client will echo what
                    408:         * WE, the server, sends it; it does NOT mean that the client will
                    409:         * echo the terminal input).
                    410:         */
                    411:        sprintf(nfrontp, doopt, TELOPT_ECHO);
                    412:        nfrontp += sizeof doopt-2;
                    413:        hisopts[TELOPT_ECHO] = OPT_YES_BUT_ALWAYS_LOOK;
                    414: 
                    415:        /*
                    416:         * Show banner that getty never gave.
                    417:         *
                    418:         * The banner includes some null's (for TELNET CR disambiguation),
                    419:         * so we have to be somewhat complicated.
                    420:         */
                    421: 
                    422:        gethostname(hostname, sizeof (hostname));
                    423: 
                    424:        bcopy(BANNER1, nfrontp, sizeof BANNER1 -1);
                    425:        nfrontp += sizeof BANNER1 - 1;
                    426:        bcopy(hostname, nfrontp, strlen(hostname));
                    427:        nfrontp += strlen(hostname);
                    428:        bcopy(BANNER2, nfrontp, sizeof BANNER2 -1);
                    429:        nfrontp += sizeof BANNER2 - 1;
                    430: 
                    431:        /*
                    432:         * Call telrcv() once to pick up anything received during
                    433:         * terminal type negotiation.
                    434:         */
                    435:        telrcv();
                    436: 
                    437:        for (;;) {
                    438:                fd_set ibits, obits, xbits;
                    439:                register int c;
                    440: 
                    441:                if (ncc < 0 && pcc < 0)
                    442:                        break;
                    443: 
                    444:                FD_ZERO(&ibits);
                    445:                FD_ZERO(&obits);
                    446:                FD_ZERO(&xbits);
                    447:                /*
                    448:                 * Never look for input if there's still
                    449:                 * stuff in the corresponding output buffer
                    450:                 */
                    451:                if (nfrontp - nbackp || pcc > 0) {
                    452:                        FD_SET(f, &obits);
                    453:                } else {
                    454:                        FD_SET(p, &ibits);
                    455:                }
                    456:                if (pfrontp - pbackp || ncc > 0) {
                    457:                        FD_SET(p, &obits);
                    458:                } else {
                    459:                        FD_SET(f, &ibits);
                    460:                }
                    461:                if (!SYNCHing) {
                    462:                        FD_SET(f, &xbits);
                    463:                }
                    464:                if ((c = select(16, &ibits, &obits, &xbits,
                    465:                                                (struct timeval *)0)) < 1) {
                    466:                        if (c == -1) {
                    467:                                if (errno == EINTR) {
                    468:                                        continue;
                    469:                                }
                    470:                        }
                    471:                        sleep(5);
                    472:                        continue;
                    473:                }
                    474: 
                    475:                /*
                    476:                 * Any urgent data?
                    477:                 */
                    478:                if (FD_ISSET(net, &xbits)) {
                    479:                    SYNCHing = 1;
                    480:                }
                    481: 
                    482:                /*
                    483:                 * Something to read from the network...
                    484:                 */
                    485:                if (FD_ISSET(net, &ibits)) {
                    486: #if    !defined(SO_OOBINLINE)
                    487:                        /*
                    488:                         * In 4.2 (and 4.3 beta) systems, the
                    489:                         * OOB indication and data handling in the kernel
                    490:                         * is such that if two separate TCP Urgent requests
                    491:                         * come in, one byte of TCP data will be overlaid.
                    492:                         * This is fatal for Telnet, but we try to live
                    493:                         * with it.
                    494:                         *
                    495:                         * In addition, in 4.2 (and...), a special protocol
                    496:                         * is needed to pick up the TCP Urgent data in
                    497:                         * the correct sequence.
                    498:                         *
                    499:                         * What we do is:  if we think we are in urgent
                    500:                         * mode, we look to see if we are "at the mark".
                    501:                         * If we are, we do an OOB receive.  If we run
                    502:                         * this twice, we will do the OOB receive twice,
                    503:                         * but the second will fail, since the second
                    504:                         * time we were "at the mark", but there wasn't
                    505:                         * any data there (the kernel doesn't reset
                    506:                         * "at the mark" until we do a normal read).
                    507:                         * Once we've read the OOB data, we go ahead
                    508:                         * and do normal reads.
                    509:                         *
                    510:                         * There is also another problem, which is that
                    511:                         * since the OOB byte we read doesn't put us
                    512:                         * out of OOB state, and since that byte is most
                    513:                         * likely the TELNET DM (data mark), we would
                    514:                         * stay in the TELNET SYNCH (SYNCHing) state.
                    515:                         * So, clocks to the rescue.  If we've "just"
                    516:                         * received a DM, then we test for the
                    517:                         * presence of OOB data when the receive OOB
                    518:                         * fails (and AFTER we did the normal mode read
                    519:                         * to clear "at the mark").
                    520:                         */
                    521:                    if (SYNCHing) {
                    522:                        int atmark;
                    523: 
                    524:                        ioctl(net, SIOCATMARK, (char *)&atmark);
                    525:                        if (atmark) {
                    526:                            ncc = recv(net, netibuf, sizeof (netibuf), MSG_OOB);
                    527:                            if ((ncc == -1) && (errno == EINVAL)) {
                    528:                                ncc = read(net, netibuf, sizeof (netibuf));
                    529:                                if (sequenceIs(didnetreceive, gotDM)) {
                    530:                                    SYNCHing = stilloob(net);
                    531:                                }
                    532:                            }
                    533:                        } else {
                    534:                            ncc = read(net, netibuf, sizeof (netibuf));
                    535:                        }
                    536:                    } else {
                    537:                        ncc = read(net, netibuf, sizeof (netibuf));
                    538:                    }
                    539:                    settimer(didnetreceive);
                    540: #else  /* !defined(SO_OOBINLINE)) */
                    541:                    ncc = read(net, netibuf, sizeof (netibuf));
                    542: #endif /* !defined(SO_OOBINLINE)) */
                    543:                    if (ncc < 0 && errno == EWOULDBLOCK)
                    544:                        ncc = 0;
                    545:                    else {
                    546:                        if (ncc <= 0) {
                    547:                            break;
                    548:                        }
                    549:                        netip = netibuf;
                    550:                    }
                    551:                }
                    552: 
                    553:                /*
                    554:                 * Something to read from the pty...
                    555:                 */
                    556:                if (FD_ISSET(p, &ibits)) {
                    557:                        pcc = read(p, ptyibuf, BUFSIZ);
                    558:                        if (pcc < 0 && errno == EWOULDBLOCK)
                    559:                                pcc = 0;
                    560:                        else {
                    561:                                if (pcc <= 0)
                    562:                                        break;
                    563:                                ptyip = ptyibuf;
                    564:                        }
                    565:                }
                    566: 
                    567:                while (pcc > 0) {
                    568:                        if ((&netobuf[BUFSIZ] - nfrontp) < 2)
                    569:                                break;
                    570:                        c = *ptyip++ & 0377, pcc--;
                    571:                        if (c == IAC)
                    572:                                *nfrontp++ = c;
                    573:                        *nfrontp++ = c;
                    574:                        if (c == '\r') {
                    575:                                if (pcc > 0 && ((*ptyip & 0377) == '\n')) {
                    576:                                        *nfrontp++ = *ptyip++ & 0377;
                    577:                                        pcc--;
                    578:                                } else
                    579:                                        *nfrontp++ = '\0';
                    580:                        }
                    581:                }
                    582:                if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0)
                    583:                        netflush();
                    584:                if (ncc > 0)
                    585:                        telrcv();
                    586:                if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0)
                    587:                        ptyflush();
                    588:        }
                    589:        cleanup();
                    590: }
                    591:        
                    592: /*
                    593:  * State for recv fsm
                    594:  */
                    595: #define        TS_DATA         0       /* base state */
                    596: #define        TS_IAC          1       /* look for double IAC's */
                    597: #define        TS_CR           2       /* CR-LF ->'s CR */
                    598: #define        TS_SB           3       /* throw away begin's... */
                    599: #define        TS_SE           4       /* ...end's (suboption negotiation) */
                    600: #define        TS_WILL         5       /* will option negotiation */
                    601: #define        TS_WONT         6       /* wont " */
                    602: #define        TS_DO           7       /* do " */
                    603: #define        TS_DONT         8       /* dont " */
                    604: 
                    605: telrcv()
                    606: {
                    607:        register int c;
                    608:        static int state = TS_DATA;
                    609: 
                    610:        while (ncc > 0) {
                    611:                if ((&ptyobuf[BUFSIZ] - pfrontp) < 2)
                    612:                        return;
                    613:                c = *netip++ & 0377, ncc--;
                    614:                switch (state) {
                    615: 
                    616:                case TS_CR:
                    617:                        state = TS_DATA;
                    618:                        if ((c == 0) || (c == '\n')) {
                    619:                                break;
                    620:                        }
                    621:                        /* FALL THROUGH */
                    622: 
                    623:                case TS_DATA:
                    624:                        if (c == IAC) {
                    625:                                state = TS_IAC;
                    626:                                break;
                    627:                        }
                    628:                        if (inter > 0)
                    629:                                break;
                    630:                        /*
                    631:                         * We map \r\n ==> \n, since \r\n says
                    632:                         * that we want to be in column 1 of the next
                    633:                         * printable line, and \n is the standard
                    634:                         * unix way of saying that (\r is only good
                    635:                         * if CRMOD is set, which it normally is).
                    636:                         */
                    637:                        if ((myopts[TELOPT_BINARY] == OPT_NO) && c == '\r') {
                    638:                                if ((ncc > 0) && ('\n' == *netip)) {
                    639:                                        netip++; ncc--;
                    640:                                        c = '\n';
                    641:                                } else {
                    642:                                        state = TS_CR;
                    643:                                }
                    644:                        }
                    645:                        *pfrontp++ = c;
                    646:                        break;
                    647: 
                    648:                case TS_IAC:
                    649:                        switch (c) {
                    650: 
                    651:                        /*
                    652:                         * Send the process on the pty side an
                    653:                         * interrupt.  Do this with a NULL or
                    654:                         * interrupt char; depending on the tty mode.
                    655:                         */
                    656:                        case IP:
                    657:                                interrupt();
                    658:                                break;
                    659: 
                    660:                        case BREAK:
                    661:                                sendbrk();
                    662:                                break;
                    663: 
                    664:                        /*
                    665:                         * Are You There?
                    666:                         */
                    667:                        case AYT:
                    668:                                strcpy(nfrontp, "\r\n[Yes]\r\n");
                    669:                                nfrontp += 9;
                    670:                                break;
                    671: 
                    672:                        /*
                    673:                         * Abort Output
                    674:                         */
                    675:                        case AO: {
                    676:                                        struct ltchars tmpltc;
                    677: 
                    678:                                        ptyflush();     /* half-hearted */
                    679:                                        ioctl(pty, TIOCGLTC, &tmpltc);
                    680:                                        if (tmpltc.t_flushc != '\377') {
                    681:                                                *pfrontp++ = tmpltc.t_flushc;
                    682:                                        }
                    683:                                        netclear();     /* clear buffer back */
                    684:                                        *nfrontp++ = IAC;
                    685:                                        *nfrontp++ = DM;
                    686:                                        neturg = nfrontp-1; /* off by one XXX */
                    687:                                        break;
                    688:                                }
                    689: 
                    690:                        /*
                    691:                         * Erase Character and
                    692:                         * Erase Line
                    693:                         */
                    694:                        case EC:
                    695:                        case EL: {
                    696:                                        struct sgttyb b;
                    697:                                        char ch;
                    698: 
                    699:                                        ptyflush();     /* half-hearted */
                    700:                                        ioctl(pty, TIOCGETP, &b);
                    701:                                        ch = (c == EC) ?
                    702:                                                b.sg_erase : b.sg_kill;
                    703:                                        if (ch != '\377') {
                    704:                                                *pfrontp++ = ch;
                    705:                                        }
                    706:                                        break;
                    707:                                }
                    708: 
                    709:                        /*
                    710:                         * Check for urgent data...
                    711:                         */
                    712:                        case DM:
                    713:                                SYNCHing = stilloob(net);
                    714:                                settimer(gotDM);
                    715:                                break;
                    716: 
                    717: 
                    718:                        /*
                    719:                         * Begin option subnegotiation...
                    720:                         */
                    721:                        case SB:
                    722:                                state = TS_SB;
                    723:                                continue;
                    724: 
                    725:                        case WILL:
                    726:                                state = TS_WILL;
                    727:                                continue;
                    728: 
                    729:                        case WONT:
                    730:                                state = TS_WONT;
                    731:                                continue;
                    732: 
                    733:                        case DO:
                    734:                                state = TS_DO;
                    735:                                continue;
                    736: 
                    737:                        case DONT:
                    738:                                state = TS_DONT;
                    739:                                continue;
                    740: 
                    741:                        case IAC:
                    742:                                *pfrontp++ = c;
                    743:                                break;
                    744:                        }
                    745:                        state = TS_DATA;
                    746:                        break;
                    747: 
                    748:                case TS_SB:
                    749:                        if (c == IAC) {
                    750:                                state = TS_SE;
                    751:                        } else {
                    752:                                SB_ACCUM(c);
                    753:                        }
                    754:                        break;
                    755: 
                    756:                case TS_SE:
                    757:                        if (c != SE) {
                    758:                                if (c != IAC) {
                    759:                                        SB_ACCUM(IAC);
                    760:                                }
                    761:                                SB_ACCUM(c);
                    762:                                state = TS_SB;
                    763:                        } else {
                    764:                                SB_TERM();
                    765:                                suboption();    /* handle sub-option */
                    766:                                state = TS_DATA;
                    767:                        }
                    768:                        break;
                    769: 
                    770:                case TS_WILL:
                    771:                        if (hisopts[c] != OPT_YES)
                    772:                                willoption(c);
                    773:                        state = TS_DATA;
                    774:                        continue;
                    775: 
                    776:                case TS_WONT:
                    777:                        if (hisopts[c] != OPT_NO)
                    778:                                wontoption(c);
                    779:                        state = TS_DATA;
                    780:                        continue;
                    781: 
                    782:                case TS_DO:
                    783:                        if (myopts[c] != OPT_YES)
                    784:                                dooption(c);
                    785:                        state = TS_DATA;
                    786:                        continue;
                    787: 
                    788:                case TS_DONT:
                    789:                        if (myopts[c] != OPT_NO) {
                    790:                                dontoption(c);
                    791:                        }
                    792:                        state = TS_DATA;
                    793:                        continue;
                    794: 
                    795:                default:
                    796:                        syslog(LOG_ERR, "telnetd: panic state=%d\n", state);
                    797:                        printf("telnetd: panic state=%d\n", state);
                    798:                        exit(1);
                    799:                }
                    800:        }
                    801: }
                    802: 
                    803: willoption(option)
                    804:        int option;
                    805: {
                    806:        char *fmt;
                    807: 
                    808:        switch (option) {
                    809: 
                    810:        case TELOPT_BINARY:
                    811:                mode(RAW, 0);
                    812:                fmt = doopt;
                    813:                break;
                    814: 
                    815:        case TELOPT_ECHO:
                    816:                not42 = 0;              /* looks like a 4.2 system */
                    817:                /*
                    818:                 * Now, in a 4.2 system, to break them out of ECHOing
                    819:                 * (to the terminal) mode, we need to send a "WILL ECHO".
                    820:                 * Kludge upon kludge!
                    821:                 */
                    822:                if (myopts[TELOPT_ECHO] == OPT_YES) {
                    823:                    dooption(TELOPT_ECHO);
                    824:                }
                    825:                fmt = dont;
                    826:                break;
                    827: 
                    828:        case TELOPT_TTYPE:
                    829:                settimer(ttypeopt);
                    830:                if (hisopts[TELOPT_TTYPE] == OPT_YES_BUT_ALWAYS_LOOK) {
                    831:                    hisopts[TELOPT_TTYPE] = OPT_YES;
                    832:                    return;
                    833:                }
                    834:                fmt = doopt;
                    835:                break;
                    836: 
                    837:        case TELOPT_SGA:
                    838:                fmt = doopt;
                    839:                break;
                    840: 
                    841:        case TELOPT_TM:
                    842:                fmt = dont;
                    843:                break;
                    844: 
                    845:        default:
                    846:                fmt = dont;
                    847:                break;
                    848:        }
                    849:        if (fmt == doopt) {
                    850:                hisopts[option] = OPT_YES;
                    851:        } else {
                    852:                hisopts[option] = OPT_NO;
                    853:        }
                    854:        sprintf(nfrontp, fmt, option);
                    855:        nfrontp += sizeof (dont) - 2;
                    856: }
                    857: 
                    858: wontoption(option)
                    859:        int option;
                    860: {
                    861:        char *fmt;
                    862: 
                    863:        switch (option) {
                    864:        case TELOPT_ECHO:
                    865:                not42 = 1;              /* doesn't seem to be a 4.2 system */
                    866:                break;
                    867: 
                    868:        case TELOPT_BINARY:
                    869:                mode(0, RAW);
                    870:                break;
                    871: 
                    872:        case TELOPT_TTYPE:
                    873:            settimer(ttypeopt);
                    874:            break;
                    875:        }
                    876: 
                    877:        fmt = dont;
                    878:        hisopts[option] = OPT_NO;
                    879:        sprintf(nfrontp, fmt, option);
                    880:        nfrontp += sizeof (doopt) - 2;
                    881: }
                    882: 
                    883: dooption(option)
                    884:        int option;
                    885: {
                    886:        char *fmt;
                    887: 
                    888:        switch (option) {
                    889: 
                    890:        case TELOPT_TM:
                    891:                fmt = wont;
                    892:                break;
                    893: 
                    894:        case TELOPT_ECHO:
                    895:                mode(ECHO|CRMOD, 0);
                    896:                fmt = will;
                    897:                break;
                    898: 
                    899:        case TELOPT_BINARY:
                    900:                mode(RAW, 0);
                    901:                fmt = will;
                    902:                break;
                    903: 
                    904:        case TELOPT_SGA:
                    905:                fmt = will;
                    906:                break;
                    907: 
                    908:        default:
                    909:                fmt = wont;
                    910:                break;
                    911:        }
                    912:        if (fmt == will) {
                    913:            myopts[option] = OPT_YES;
                    914:        } else {
                    915:            myopts[option] = OPT_NO;
                    916:        }
                    917:        sprintf(nfrontp, fmt, option);
                    918:        nfrontp += sizeof (doopt) - 2;
                    919: }
                    920: 
                    921: 
                    922: dontoption(option)
                    923: int option;
                    924: {
                    925:     char *fmt;
                    926: 
                    927:     switch (option) {
                    928:     case TELOPT_ECHO:          /* we should stop echoing */
                    929:        mode(0, ECHO|CRMOD);
                    930:        fmt = wont;
                    931:        break;
                    932: 
                    933:     default:
                    934:        fmt = wont;
                    935:        break;
                    936:     }
                    937: 
                    938:     if (fmt = wont) {
                    939:        myopts[option] = OPT_NO;
                    940:     } else {
                    941:        myopts[option] = OPT_YES;
                    942:     }
                    943:     sprintf(nfrontp, fmt, option);
                    944:     nfrontp += sizeof (wont) - 2;
                    945: }
                    946: 
                    947: /*
                    948:  * suboption()
                    949:  *
                    950:  *     Look at the sub-option buffer, and try to be helpful to the other
                    951:  * side.
                    952:  *
                    953:  *     Currently we recognize:
                    954:  *
                    955:  *     Terminal type is
                    956:  */
                    957: 
                    958: suboption()
                    959: {
                    960:     switch (SB_GET()) {
                    961:     case TELOPT_TTYPE: {               /* Yaaaay! */
                    962:        static char terminalname[5+41] = "TERM=";
                    963: 
                    964:        settimer(ttypesubopt);
                    965: 
                    966:        if (SB_GET() != TELQUAL_IS) {
                    967:            return;             /* ??? XXX but, this is the most robust */
                    968:        }
                    969: 
                    970:        terminaltype = terminalname+strlen(terminalname);
                    971: 
                    972:        while ((terminaltype < (terminalname + sizeof terminalname-1)) &&
                    973:                                                                    !SB_EOF()) {
                    974:            register int c;
                    975: 
                    976:            c = SB_GET();
                    977:            if (isupper(c)) {
                    978:                c = tolower(c);
                    979:            }
                    980:            *terminaltype++ = c;    /* accumulate name */
                    981:        }
                    982:        *terminaltype = 0;
                    983:        terminaltype = terminalname;
                    984:        break;
                    985:     }
                    986: 
                    987:     default:
                    988:        ;
                    989:     }
                    990: }
                    991: 
                    992: mode(on, off)
                    993:        int on, off;
                    994: {
                    995:        struct sgttyb b;
                    996: 
                    997:        ptyflush();
                    998:        ioctl(pty, TIOCGETP, &b);
                    999:        b.sg_flags |= on;
                   1000:        b.sg_flags &= ~off;
                   1001:        ioctl(pty, TIOCSETP, &b);
                   1002: }
                   1003: 
                   1004: /*
                   1005:  * Send interrupt to process on other side of pty.
                   1006:  * If it is in raw mode, just write NULL;
                   1007:  * otherwise, write intr char.
                   1008:  */
                   1009: interrupt()
                   1010: {
                   1011:        struct sgttyb b;
                   1012:        struct tchars tchars;
                   1013: 
                   1014:        ptyflush();     /* half-hearted */
                   1015:        ioctl(pty, TIOCGETP, &b);
                   1016:        if (b.sg_flags & RAW) {
                   1017:                *pfrontp++ = '\0';
                   1018:                return;
                   1019:        }
                   1020:        *pfrontp++ = ioctl(pty, TIOCGETC, &tchars) < 0 ?
                   1021:                '\177' : tchars.t_intrc;
                   1022: }
                   1023: 
                   1024: /*
                   1025:  * Send quit to process on other side of pty.
                   1026:  * If it is in raw mode, just write NULL;
                   1027:  * otherwise, write quit char.
                   1028:  */
                   1029: sendbrk()
                   1030: {
                   1031:        struct sgttyb b;
                   1032:        struct tchars tchars;
                   1033: 
                   1034:        ptyflush();     /* half-hearted */
                   1035:        ioctl(pty, TIOCGETP, &b);
                   1036:        if (b.sg_flags & RAW) {
                   1037:                *pfrontp++ = '\0';
                   1038:                return;
                   1039:        }
                   1040:        *pfrontp++ = ioctl(pty, TIOCGETC, &tchars) < 0 ?
                   1041:                '\034' : tchars.t_quitc;
                   1042: }
                   1043: 
                   1044: ptyflush()
                   1045: {
                   1046:        int n;
                   1047: 
                   1048:        if ((n = pfrontp - pbackp) > 0)
                   1049:                n = write(pty, pbackp, n);
                   1050:        if (n < 0)
                   1051:                return;
                   1052:        pbackp += n;
                   1053:        if (pbackp == pfrontp)
                   1054:                pbackp = pfrontp = ptyobuf;
                   1055: }
                   1056: 
                   1057: /*
                   1058:  * nextitem()
                   1059:  *
                   1060:  *     Return the address of the next "item" in the TELNET data
                   1061:  * stream.  This will be the address of the next character if
                   1062:  * the current address is a user data character, or it will
                   1063:  * be the address of the character following the TELNET command
                   1064:  * if the current address is a TELNET IAC ("I Am a Command")
                   1065:  * character.
                   1066:  */
                   1067: 
                   1068: char *
                   1069: nextitem(current)
                   1070: char   *current;
                   1071: {
                   1072:     if ((*current&0xff) != IAC) {
                   1073:        return current+1;
                   1074:     }
                   1075:     switch (*(current+1)&0xff) {
                   1076:     case DO:
                   1077:     case DONT:
                   1078:     case WILL:
                   1079:     case WONT:
                   1080:        return current+3;
                   1081:     case SB:           /* loop forever looking for the SE */
                   1082:        {
                   1083:            register char *look = current+2;
                   1084: 
                   1085:            for (;;) {
                   1086:                if ((*look++&0xff) == IAC) {
                   1087:                    if ((*look++&0xff) == SE) {
                   1088:                        return look;
                   1089:                    }
                   1090:                }
                   1091:            }
                   1092:        }
                   1093:     default:
                   1094:        return current+2;
                   1095:     }
                   1096: }
                   1097: 
                   1098: 
                   1099: /*
                   1100:  * netclear()
                   1101:  *
                   1102:  *     We are about to do a TELNET SYNCH operation.  Clear
                   1103:  * the path to the network.
                   1104:  *
                   1105:  *     Things are a bit tricky since we may have sent the first
                   1106:  * byte or so of a previous TELNET command into the network.
                   1107:  * So, we have to scan the network buffer from the beginning
                   1108:  * until we are up to where we want to be.
                   1109:  *
                   1110:  *     A side effect of what we do, just to keep things
                   1111:  * simple, is to clear the urgent data pointer.  The principal
                   1112:  * caller should be setting the urgent data pointer AFTER calling
                   1113:  * us in any case.
                   1114:  */
                   1115: 
                   1116: netclear()
                   1117: {
                   1118:     register char *thisitem, *next;
                   1119:     char *good;
                   1120: #define        wewant(p)       ((nfrontp > p) && ((*p&0xff) == IAC) && \
                   1121:                                ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
                   1122: 
                   1123:     thisitem = netobuf;
                   1124: 
                   1125:     while ((next = nextitem(thisitem)) <= nbackp) {
                   1126:        thisitem = next;
                   1127:     }
                   1128: 
                   1129:     /* Now, thisitem is first before/at boundary. */
                   1130: 
                   1131:     good = netobuf;    /* where the good bytes go */
                   1132: 
                   1133:     while (nfrontp > thisitem) {
                   1134:        if (wewant(thisitem)) {
                   1135:            int length;
                   1136: 
                   1137:            next = thisitem;
                   1138:            do {
                   1139:                next = nextitem(next);
                   1140:            } while (wewant(next) && (nfrontp > next));
                   1141:            length = next-thisitem;
                   1142:            bcopy(thisitem, good, length);
                   1143:            good += length;
                   1144:            thisitem = next;
                   1145:        } else {
                   1146:            thisitem = nextitem(thisitem);
                   1147:        }
                   1148:     }
                   1149: 
                   1150:     nbackp = netobuf;
                   1151:     nfrontp = good;            /* next byte to be sent */
                   1152:     neturg = 0;
                   1153: }
                   1154: 
                   1155: /*
                   1156:  *  netflush
                   1157:  *             Send as much data as possible to the network,
                   1158:  *     handling requests for urgent data.
                   1159:  */
                   1160: 
                   1161: 
                   1162: netflush()
                   1163: {
                   1164:     int n;
                   1165: 
                   1166:     if ((n = nfrontp - nbackp) > 0) {
                   1167:        /*
                   1168:         * if no urgent data, or if the other side appears to be an
                   1169:         * old 4.2 client (and thus unable to survive TCP urgent data),
                   1170:         * write the entire buffer in non-OOB mode.
                   1171:         */
                   1172:        if ((neturg == 0) || (not42 == 0)) {
                   1173:            n = write(net, nbackp, n);  /* normal write */
                   1174:        } else {
                   1175:            n = neturg - nbackp;
                   1176:            /*
                   1177:             * In 4.2 (and 4.3) systems, there is some question about
                   1178:             * what byte in a sendOOB operation is the "OOB" data.
                   1179:             * To make ourselves compatible, we only send ONE byte
                   1180:             * out of band, the one WE THINK should be OOB (though
                   1181:             * we really have more the TCP philosophy of urgent data
                   1182:             * rather than the Unix philosophy of OOB data).
                   1183:             */
                   1184:            if (n > 1) {
                   1185:                n = send(net, nbackp, n-1, 0);  /* send URGENT all by itself */
                   1186:            } else {
                   1187:                n = send(net, nbackp, n, MSG_OOB);      /* URGENT data */
                   1188:            }
                   1189:        }
                   1190:     }
                   1191:     if (n < 0) {
                   1192:        if (errno == EWOULDBLOCK)
                   1193:            return;
                   1194:        /* should blow this guy away... */
                   1195:        return;
                   1196:     }
                   1197:     nbackp += n;
                   1198:     if (nbackp >= neturg) {
                   1199:        neturg = 0;
                   1200:     }
                   1201:     if (nbackp == nfrontp) {
                   1202:        nbackp = nfrontp = netobuf;
                   1203:     }
                   1204: }
                   1205: 
                   1206: cleanup()
                   1207: {
                   1208: 
                   1209:        rmut();
                   1210:        vhangup();      /* XXX */
                   1211:        shutdown(net, 2);
                   1212:        exit(1);
                   1213: }
                   1214: 
                   1215: #include <utmp.h>
                   1216: 
                   1217: struct utmp wtmp;
                   1218: char   wtmpf[] = "/usr/adm/wtmp";
                   1219: char   utmpf[] = "/etc/utmp";
                   1220: #define SCPYN(a, b)    strncpy(a, b, sizeof(a))
                   1221: #define SCMPN(a, b)    strncmp(a, b, sizeof(a))
                   1222: 
                   1223: rmut()
                   1224: {
                   1225:        register f;
                   1226:        int found = 0;
                   1227:        struct utmp *u, *utmp;
                   1228:        int nutmp;
                   1229:        struct stat statbf;
                   1230: 
                   1231:        f = open(utmpf, O_RDWR);
                   1232:        if (f >= 0) {
                   1233:                fstat(f, &statbf);
                   1234:                utmp = (struct utmp *)malloc(statbf.st_size);
                   1235:                if (!utmp)
                   1236:                        syslog(LOG_ERR, "utmp malloc failed");
                   1237:                if (statbf.st_size && utmp) {
                   1238:                        nutmp = read(f, utmp, statbf.st_size);
                   1239:                        nutmp /= sizeof(struct utmp);
                   1240:                
                   1241:                        for (u = utmp ; u < &utmp[nutmp] ; u++) {
                   1242:                                if (SCMPN(u->ut_line, line+5) ||
                   1243:                                    u->ut_name[0]==0)
                   1244:                                        continue;
                   1245:                                lseek(f, ((long)u)-((long)utmp), L_SET);
                   1246:                                SCPYN(u->ut_name, "");
                   1247:                                SCPYN(u->ut_host, "");
                   1248:                                time(&u->ut_time);
                   1249:                                write(f, (char *)u, sizeof(wtmp));
                   1250:                                found++;
                   1251:                        }
                   1252:                }
                   1253:                close(f);
                   1254:        }
                   1255:        if (found) {
                   1256:                f = open(wtmpf, O_WRONLY|O_APPEND);
                   1257:                if (f >= 0) {
                   1258:                        SCPYN(wtmp.ut_line, line+5);
                   1259:                        SCPYN(wtmp.ut_name, "");
                   1260:                        SCPYN(wtmp.ut_host, "");
                   1261:                        time(&wtmp.ut_time);
                   1262:                        write(f, (char *)&wtmp, sizeof(wtmp));
                   1263:                        close(f);
                   1264:                }
                   1265:        }
                   1266:        chmod(line, 0666);
                   1267:        chown(line, 0, 0);
                   1268:        line[strlen("/dev/")] = 'p';
                   1269:        chmod(line, 0666);
                   1270:        chown(line, 0, 0);
                   1271: }

unix.superglobalmegacorp.com

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