Annotation of 43BSDTahoe/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.
                      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.