Annotation of 43BSDTahoe/etc/telnetd.c, revision 1.1

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

unix.superglobalmegacorp.com

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