# 2.11BSD#431 - /usr/src/libexec/telnetd/telnetd.c

##### Functions

    cleanup           X
    doit              X
    dontoption        X
    dooption          X
    fatal             X
    fatalperror       X
    getterminaltype   X
    interrupt         X
    main              X
    mode              X
    netclear          X
    netflush          X
    nextitem          X
    ptyflush          X
    rmut              X
    sendbrk           X
    stilloob          X
    suboption         X
    telnet            X
    telrcv            X
    ttloop            X
    willoption        X
    wontoption        X

##### Variables

    BANNER1           X
    SYNCHing          X
    copyright         X
    dont              X
    doopt             X
    envinit           X
    hisopts           X
    inter             X
    line              X
    myopts            X
    ncc               X
    net               X
    netibuf           X
    netip             X
    netobuf           X
    neturg            X
    nfrontp           X
    not42             X
    pcc               X
    pfrontp           X
    pty               X
    ptyibuf           X
    ptyip             X
    ptyobuf           X
    subbuffer         X
    subpointer        X
    terminaltype      X
    utmpf             X
    will              X
    wont              X
    wtmp              X
    wtmpf             X

##### Macros

    NIACCUM           X
    OPT_NO            X
    OPT_NO_BUT_ALWAYS_LOOKX
    OPT_YES           X
    OPT_YES_BUT_ALWAYS_LOOKX
    SB_ACCUM          X
    SB_CLEAR          X
    SB_EOF            X
    SB_GET            X
    SB_TERM           X
    SCMPN             X
    SCPYN             X
    TS_CR             X
    TS_DATA           X
    TS_DO             X
    TS_DONT           X
    TS_IAC            X
    TS_SB             X
    TS_SE             X
    TS_WILL           X
    TS_WONT           X
    sequenceIs        X
    settimer          X
    wewant            X

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

#### Defined functions

cleanup defined in line 1220; used 3 times

- in line 170, 394, 603

doit defined in line 236; used 1 times

- in line 165

dontoption defined in line 936; used 1 times

- in line 804

dooption defined in line 897; used 4 times

- in line 401-404(2), 798, 837

fatal defined in line 328; used 2 times

- in line 261, 346

fatalperror defined in line 339; used 6 times

- in line 273-275(2), 281, 304, 324, 369

getterminaltype defined in line 210; used 1 times

- in line 301

interrupt defined in line 1023; used 1 times

- in line 671

main defined in line 108; never used
mode defined in line 1006; used 5 times

- in line 825, 883, 909-914(2), 943

netclear defined in line 1130; used 2 times

- in line 570, 697

netflush defined in line 1176; used 2 times

- in line 185, 597

nextitem defined in line 1082; used 3 times

- in line 1139, 1153, 1160

ptyflush defined in line 1058; used 6 times

- in line 601, 692, 713, 1011, 1028, 1048

rmut defined in line 1237; used 1 times

- in line 1223

sendbrk defined in line 1043; used 1 times

- in line 675

stilloob defined in line 355; used 2 times

- in line 535, 727

suboption defined in line 972; used 1 times

- in line 779

telnet defined in line 382; used 1 times

- in line 306

telrcv defined in line 619; used 4 times

- in line 196-199(2), 440, 599

ttloop defined in line 181; used 2 times

- in line 220, 228

willoption defined in line 817; used 1 times

- in line 786

wontoption defined in line 872; used 1 times

- in line 792

#### Defined variables

BANNER1 defined in line 67; used 3 times

- in line 429-430(3)

SYNCHing defined in line 87; used 5 times

- in line 466, 484, 526, 535, 727

copyright defined in line 8; never used
dont defined in line 45; used 5 times

- in line 839, 856-860(2), 869, 891

doopt defined in line 44; used 8 times

- in line 416-417(2), 826, 848-852(2), 863, 894, 932

envinit defined in line 169; used 3 times

- in line 313-315(3)

hisopts defined in line 41; used 11 times

- in line 218-222(2), 418, 656, 785, 791, 844-845(2), 864-866(2), 892

inter defined in line 83; used 1 times

- in line 643

line defined in line 86; used 19 times

- in line 249-256(6), 265, 271-281(5), 1256, 1272, 1280-1284(5)

myopts defined in line 42; used 10 times

- in line 400-403(2), 588, 797, 803, 836, 927-929(2), 953-955(2)

ncc defined in line 80; used 19 times

- in line 58, 187-191(3), 197, 446, 461, 531-533(3), 539-551(6), 598, 624-627(2)

net defined in line 82; used 17 times

- in line 187, 295, 391, 483, 490, 529-546(7), 727, 1187, 1199-1201(2), 1225

netibuf defined in line 56; used 15 times

- in line 56, 187(2), 195, 531-533(4), 539-546(6), 554

netip defined in line 56; used 4 times

- in line 57, 195, 554, 627

netobuf defined in line 61; used 7 times

- in line 61(2), 581, 1137, 1145, 1164, 1216

neturg defined in line 62; used 7 times

- in line 573, 700, 1166, 1186-1189(2), 1212-1213(2)

nfrontp defined in line 61; used 43 times

- in line 184, 216-217(2), 225-226(2), 416-417(2), 429-434(6), 456, 571-573(3), 581-596(6), 682-683(2), 698-700(3), 868-869(2), 893-894(2), 931-932(2), 957-958(2), 1134, 1147, 1154, 1165, 1180, 1215-1216(2)

not42 defined in line 64; used 3 times

- in line 830, 879, 1186

pcc defined in line 80; used 11 times

- in line 446, 456, 562-566(4), 575-583(3), 589-591(2)

pfrontp defined in line 54; used 15 times

- in line 198, 461, 600, 625, 659, 695, 718, 756, 1031-1034(2), 1051-1054(2), 1062-1068(3)

pty defined in line 82; used 11 times

- in line 296, 369, 693, 714, 1012-1015(2), 1029-1034(2), 1049-1054(2), 1063

ptyibuf defined in line 52; used 4 times

- in line 52, 562, 568, 576

ptyip defined in line 52; used 4 times

- in line 576, 583, 589-590(2)

ptyobuf defined in line 54; used 5 times

- in line 54(2), 198, 625, 1068

sccsid defined in line 12; never used
subbuffer defined in line 71; used 5 times

- in line 71-74(5)

subpointer defined in line 71; used 6 times

- in line 72-78(6)

terminaltype defined in line 168; used 7 times

- in line 313, 323, 984-986(2), 994-997(3)

utmpf defined in line 1233; used 1 times

- in line 1245

will defined in line 46; used 4 times

- in line 910-919(3), 926

wont defined in line 47; used 6 times

- in line 905, 923, 944-952(3), 958

wtmp defined in line 1231; used 7 times

- in line 1263, 1272-1276(6)

wtmpf defined in line 1232; used 1 times

- in line 1270

#### Defined macros

NIACCUM defined in line 57; never used
OPT_NO defined in line 37; used 8 times

- in line 588, 656, 791, 803, 866, 892, 929, 953

OPT_NO_BUT_ALWAYS_LOOK defined in line 40; never used
OPT_YES defined in line 38; used 8 times

- in line 222, 785, 797, 836, 845, 864, 927, 955

OPT_YES_BUT_ALWAYS_LOOK defined in line 39; used 3 times

- in line 218, 418, 844

SB_ACCUM defined in line 74; used 3 times

- in line 766, 773-775(2)

SB_CLEAR defined in line 72; used 1 times

- in line 73

SB_EOF defined in line 78; used 1 times

- in line 987

SB_GET defined in line 77; used 3 times

- in line 974, 980, 990

SB_TERM defined in line 73; used 1 times

- in line 778

SCMPN defined in line 1235; used 1 times

- in line 1256

SCPYN defined in line 1234; used 5 times

- in line 1260-1261(2), 1272-1274(3)

TS_CR defined in line 611; used 1 times

- in line 657

TS_DATA defined in line 609; used 8 times

- in line 622, 631, 759, 780, 787, 793, 799, 806

TS_DO defined in line 616; used 1 times

- in line 748

TS_DONT defined in line 617; used 1 times

- in line 752

TS_IAC defined in line 610; used 1 times

- in line 640

TS_SB defined in line 612; used 2 times

- in line 736, 776

TS_SE defined in line 613; used 1 times

- in line 764

TS_WILL defined in line 614; used 1 times

- in line 740

TS_WONT defined in line 615; used 1 times

- in line 744

sequenceIs defined in line 106; used 3 times

- in line 219, 227, 534

settimer defined in line 105; used 6 times

- in line 215, 544, 728, 843, 887, 978

wewant defined in line 1134; used 2 times

- in line 1148, 1154

Last modified: 1996-11-17 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 5409 |