home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / security / logdaemon-2 / telnetd / telnetd.c- < prev    next >
Encoding:
Text File  |  1989-02-23  |  27.3 KB  |  1,380 lines

  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.31 (Berkeley) 2/23/89";
  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.     syslog(LOG_ERR, "/bin/login: %m\n");
  336.     fatalperror(2, "/bin/login");
  337.     /*NOTREACHED*/
  338. }
  339.  
  340. fatal(f, msg)
  341.     int f;
  342.     char *msg;
  343. {
  344.     char buf[BUFSIZ];
  345.  
  346.     (void) sprintf(buf, "telnetd: %s.\r\n", msg);
  347.     (void) write(f, buf, strlen(buf));
  348.     exit(1);
  349. }
  350.  
  351. fatalperror(f, msg)
  352.     int f;
  353.     char *msg;
  354. {
  355.     char buf[BUFSIZ];
  356.     extern char *sys_errlist[];
  357.  
  358.     (void) sprintf(buf, "%s: %s\r\n", msg, sys_errlist[errno]);
  359.     fatal(f, buf);
  360. }
  361.  
  362.  
  363. /*
  364.  * Check a descriptor to see if out of band data exists on it.
  365.  */
  366.  
  367.  
  368. stilloob(s)
  369. int    s;        /* socket number */
  370. {
  371.     static struct timeval timeout = { 0 };
  372.     fd_set    excepts;
  373.     int value;
  374.  
  375.     do {
  376.     FD_ZERO(&excepts);
  377.     FD_SET(s, &excepts);
  378.     value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);
  379.     } while ((value == -1) && (errno == EINTR));
  380.  
  381.     if (value < 0) {
  382.     fatalperror(pty, "select");
  383.     }
  384.     if (FD_ISSET(s, &excepts)) {
  385.     return 1;
  386.     } else {
  387.     return 0;
  388.     }
  389. }
  390.  
  391. /*
  392.  * Main loop.  Select from pty and network, and
  393.  * hand data to telnet receiver finite state machine.
  394.  */
  395. telnet(f, p)
  396. {
  397.     int on = 1;
  398.     char hostname[MAXHOSTNAMELEN];
  399. #define    TABBUFSIZ    512
  400.     char    defent[TABBUFSIZ];
  401.     char    defstrs[TABBUFSIZ];
  402. #undef    TABBUFSIZ
  403.     char *HE;
  404.     char *HN;
  405.     char *IM;
  406.  
  407.     ioctl(f, FIONBIO, &on);
  408.     ioctl(p, FIONBIO, &on);
  409.     ioctl(p, TIOCPKT, &on);
  410. #if    defined(SO_OOBINLINE)
  411.     setsockopt(net, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
  412. #endif    /* defined(SO_OOBINLINE) */
  413.     signal(SIGTSTP, SIG_IGN);
  414.     /*
  415.      * Ignoring SIGTTOU keeps the kernel from blocking us
  416.      * in ttioctl() in /sys/tty.c.
  417.      */
  418.     signal(SIGTTOU, SIG_IGN);
  419.     signal(SIGCHLD, cleanup);
  420.     setpgrp(0, 0);
  421.  
  422.     /*
  423.      * Request to do remote echo and to suppress go ahead.
  424.      */
  425.     if (!myopts[TELOPT_ECHO]) {
  426.         dooption(TELOPT_ECHO);
  427.     }
  428.     if (!myopts[TELOPT_SGA]) {
  429.         dooption(TELOPT_SGA);
  430.     }
  431.     /*
  432.      * Is the client side a 4.2 (NOT 4.3) system?  We need to know this
  433.      * because 4.2 clients are unable to deal with TCP urgent data.
  434.      *
  435.      * To find out, we send out a "DO ECHO".  If the remote system
  436.      * answers "WILL ECHO" it is probably a 4.2 client, and we note
  437.      * that fact ("WILL ECHO" ==> that the client will echo what
  438.      * WE, the server, sends it; it does NOT mean that the client will
  439.      * echo the terminal input).
  440.      */
  441.     (void) sprintf(nfrontp, doopt, TELOPT_ECHO);
  442.     nfrontp += sizeof doopt-2;
  443.     hisopts[TELOPT_ECHO] = OPT_YES_BUT_ALWAYS_LOOK;
  444.  
  445.     /*
  446.      * Show banner that getty never gave.
  447.      *
  448.      * We put the banner in the pty input buffer.  This way, it
  449.      * gets carriage return null processing, etc., just like all
  450.      * other pty --> client data.
  451.      */
  452.  
  453.     gethostname(hostname, sizeof (hostname));
  454.     if (getent(defent, "default") == 1) {
  455.         char *getstr();
  456.         char *p=defstrs;
  457.  
  458.         HE = getstr("he", &p);
  459.         HN = getstr("hn", &p);
  460.         IM = getstr("im", &p);
  461.         if (HN && *HN)
  462.             strcpy(hostname, HN);
  463.         edithost(HE, hostname);
  464.         if (IM && *IM)
  465.             putf(IM, ptyibuf+1);
  466.     } else {
  467.         sprintf(ptyibuf+1, BANNER, hostname);
  468.     }
  469.  
  470.     ptyip = ptyibuf+1;        /* Prime the pump */
  471.     pcc = strlen(ptyip);        /* ditto */
  472.  
  473.     /* Clear ptybuf[0] - where the packet information is received */
  474.     ptyibuf[0] = 0;
  475.  
  476.     /*
  477.      * Call telrcv() once to pick up anything received during
  478.      * terminal type negotiation.
  479.      */
  480.     telrcv();
  481.  
  482.     for (;;) {
  483.         fd_set ibits, obits, xbits;
  484.         register int c;
  485.  
  486.         if (ncc < 0 && pcc < 0)
  487.             break;
  488.  
  489.         FD_ZERO(&ibits);
  490.         FD_ZERO(&obits);
  491.         FD_ZERO(&xbits);
  492.         /*
  493.          * Never look for input if there's still
  494.          * stuff in the corresponding output buffer
  495.          */
  496.         if (nfrontp - nbackp || pcc > 0) {
  497.             FD_SET(f, &obits);
  498.             FD_SET(p, &xbits);
  499.         } else {
  500.             FD_SET(p, &ibits);
  501.         }
  502.         if (pfrontp - pbackp || ncc > 0) {
  503.             FD_SET(p, &obits);
  504.         } else {
  505.             FD_SET(f, &ibits);
  506.         }
  507.         if (!SYNCHing) {
  508.             FD_SET(f, &xbits);
  509.         }
  510.         if ((c = select(16, &ibits, &obits, &xbits,
  511.                         (struct timeval *)0)) < 1) {
  512.             if (c == -1) {
  513.                 if (errno == EINTR) {
  514.                     continue;
  515.                 }
  516.             }
  517.             sleep(5);
  518.             continue;
  519.         }
  520.  
  521.         /*
  522.          * Any urgent data?
  523.          */
  524.         if (FD_ISSET(net, &xbits)) {
  525.             SYNCHing = 1;
  526.         }
  527.  
  528.         /*
  529.          * Something to read from the network...
  530.          */
  531.         if (FD_ISSET(net, &ibits)) {
  532. #if    !defined(SO_OOBINLINE)
  533.             /*
  534.              * In 4.2 (and 4.3 beta) systems, the
  535.              * OOB indication and data handling in the kernel
  536.              * is such that if two separate TCP Urgent requests
  537.              * come in, one byte of TCP data will be overlaid.
  538.              * This is fatal for Telnet, but we try to live
  539.              * with it.
  540.              *
  541.              * In addition, in 4.2 (and...), a special protocol
  542.              * is needed to pick up the TCP Urgent data in
  543.              * the correct sequence.
  544.              *
  545.              * What we do is:  if we think we are in urgent
  546.              * mode, we look to see if we are "at the mark".
  547.              * If we are, we do an OOB receive.  If we run
  548.              * this twice, we will do the OOB receive twice,
  549.              * but the second will fail, since the second
  550.              * time we were "at the mark", but there wasn't
  551.              * any data there (the kernel doesn't reset
  552.              * "at the mark" until we do a normal read).
  553.              * Once we've read the OOB data, we go ahead
  554.              * and do normal reads.
  555.              *
  556.              * There is also another problem, which is that
  557.              * since the OOB byte we read doesn't put us
  558.              * out of OOB state, and since that byte is most
  559.              * likely the TELNET DM (data mark), we would
  560.              * stay in the TELNET SYNCH (SYNCHing) state.
  561.              * So, clocks to the rescue.  If we've "just"
  562.              * received a DM, then we test for the
  563.              * presence of OOB data when the receive OOB
  564.              * fails (and AFTER we did the normal mode read
  565.              * to clear "at the mark").
  566.              */
  567.             if (SYNCHing) {
  568.             int atmark;
  569.  
  570.             ioctl(net, SIOCATMARK, (char *)&atmark);
  571.             if (atmark) {
  572.                 ncc = recv(net, netibuf, sizeof (netibuf), MSG_OOB);
  573.                 if ((ncc == -1) && (errno == EINVAL)) {
  574.                 ncc = read(net, netibuf, sizeof (netibuf));
  575.                 if (sequenceIs(didnetreceive, gotDM)) {
  576.                     SYNCHing = stilloob(net);
  577.                 }
  578.                 }
  579.             } else {
  580.                 ncc = read(net, netibuf, sizeof (netibuf));
  581.             }
  582.             } else {
  583.             ncc = read(net, netibuf, sizeof (netibuf));
  584.             }
  585.             settimer(didnetreceive);
  586. #else    /* !defined(SO_OOBINLINE)) */
  587.             ncc = read(net, netibuf, sizeof (netibuf));
  588. #endif    /* !defined(SO_OOBINLINE)) */
  589.             if (ncc < 0 && errno == EWOULDBLOCK)
  590.             ncc = 0;
  591.             else {
  592.             if (ncc <= 0) {
  593.                 break;
  594.             }
  595.             netip = netibuf;
  596.             }
  597.         }
  598.  
  599.         /*
  600.          * Something to read from the pty...
  601.          */
  602.         if (FD_ISSET(p, &xbits)) {
  603.             if (read(p, ptyibuf, 1) != 1) {
  604.                 break;
  605.             }
  606.         }
  607.         if (FD_ISSET(p, &ibits)) {
  608.             pcc = read(p, ptyibuf, BUFSIZ);
  609.             if (pcc < 0 && errno == EWOULDBLOCK)
  610.                 pcc = 0;
  611.             else {
  612.                 if (pcc <= 0)
  613.                     break;
  614.                 /* Skip past "packet" */
  615.                 pcc--;
  616.                 ptyip = ptyibuf+1;
  617.             }
  618.         }
  619.         if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) {
  620.             netclear();    /* clear buffer back */
  621.             *nfrontp++ = IAC;
  622.             *nfrontp++ = DM;
  623.             neturg = nfrontp-1;  /* off by one XXX */
  624.             ptyibuf[0] = 0;
  625.         }
  626.  
  627.         while (pcc > 0) {
  628.             if ((&netobuf[BUFSIZ] - nfrontp) < 2)
  629.                 break;
  630.             c = *ptyip++ & 0377, pcc--;
  631.             if (c == IAC)
  632.                 *nfrontp++ = c;
  633.             *nfrontp++ = c;
  634.             /* Don't do CR-NUL if we are in binary mode */
  635.             if ((c == '\r') && (myopts[TELOPT_BINARY] == OPT_NO)) {
  636.                 if (pcc > 0 && ((*ptyip & 0377) == '\n')) {
  637.                     *nfrontp++ = *ptyip++ & 0377;
  638.                     pcc--;
  639.                 } else
  640.                     *nfrontp++ = '\0';
  641.             }
  642.         }
  643.         if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0)
  644.             netflush();
  645.         if (ncc > 0)
  646.             telrcv();
  647.         if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0)
  648.             ptyflush();
  649.     }
  650.     cleanup();
  651. }
  652.     
  653. /*
  654.  * State for recv fsm
  655.  */
  656. #define    TS_DATA        0    /* base state */
  657. #define    TS_IAC        1    /* look for double IAC's */
  658. #define    TS_CR        2    /* CR-LF ->'s CR */
  659. #define    TS_SB        3    /* throw away begin's... */
  660. #define    TS_SE        4    /* ...end's (suboption negotiation) */
  661. #define    TS_WILL        5    /* will option negotiation */
  662. #define    TS_WONT        6    /* wont " */
  663. #define    TS_DO        7    /* do " */
  664. #define    TS_DONT        8    /* dont " */
  665.  
  666. telrcv()
  667. {
  668.     register int c;
  669.     static int state = TS_DATA;
  670.  
  671.     while (ncc > 0) {
  672.         if ((&ptyobuf[BUFSIZ] - pfrontp) < 2)
  673.             return;
  674.         c = *netip++ & 0377, ncc--;
  675.         switch (state) {
  676.  
  677.         case TS_CR:
  678.             state = TS_DATA;
  679.             /* Strip off \n or \0 after a \r */
  680.             if ((c == 0) || (c == '\n')) {
  681.                 break;
  682.             }
  683.             /* FALL THROUGH */
  684.  
  685.         case TS_DATA:
  686.             if (c == IAC) {
  687.                 state = TS_IAC;
  688.                 break;
  689.             }
  690.             if (inter > 0)
  691.                 break;
  692.             /*
  693.              * We now map \r\n ==> \r for pragmatic reasons.
  694.              * Many client implementations send \r\n when
  695.              * the user hits the CarriageReturn key.
  696.              *
  697.              * We USED to map \r\n ==> \n, since \r\n says
  698.              * that we want to be in column 1 of the next
  699.              * printable line, and \n is the standard
  700.              * unix way of saying that (\r is only good
  701.              * if CRMOD is set, which it normally is).
  702.              */
  703.             if ((c == '\r') && (hisopts[TELOPT_BINARY] == OPT_NO)) {
  704.                 state = TS_CR;
  705.             }
  706.             *pfrontp++ = c;
  707.             break;
  708.  
  709.         case TS_IAC:
  710.             switch (c) {
  711.  
  712.             /*
  713.              * Send the process on the pty side an
  714.              * interrupt.  Do this with a NULL or
  715.              * interrupt char; depending on the tty mode.
  716.              */
  717.             case IP:
  718.                 interrupt();
  719.                 break;
  720.  
  721.             case BREAK:
  722.                 sendbrk();
  723.                 break;
  724.  
  725.             /*
  726.              * Are You There?
  727.              */
  728.             case AYT:
  729.                 strcpy(nfrontp, "\r\n[Yes]\r\n");
  730.                 nfrontp += 9;
  731.                 break;
  732.  
  733.             /*
  734.              * Abort Output
  735.              */
  736.             case AO: {
  737.                     struct ltchars tmpltc;
  738.  
  739.                     ptyflush();    /* half-hearted */
  740.                     ioctl(pty, TIOCGLTC, &tmpltc);
  741.                     if (tmpltc.t_flushc != '\377') {
  742.                         *pfrontp++ = tmpltc.t_flushc;
  743.                     }
  744.                     netclear();    /* clear buffer back */
  745.                     *nfrontp++ = IAC;
  746.                     *nfrontp++ = DM;
  747.                     neturg = nfrontp-1; /* off by one XXX */
  748.                     break;
  749.                 }
  750.  
  751.             /*
  752.              * Erase Character and
  753.              * Erase Line
  754.              */
  755.             case EC:
  756.             case EL: {
  757.                     struct sgttyb b;
  758.                     char ch;
  759.  
  760.                     ptyflush();    /* half-hearted */
  761.                     ioctl(pty, TIOCGETP, &b);
  762.                     ch = (c == EC) ?
  763.                         b.sg_erase : b.sg_kill;
  764.                     if (ch != '\377') {
  765.                         *pfrontp++ = ch;
  766.                     }
  767.                     break;
  768.                 }
  769.  
  770.             /*
  771.              * Check for urgent data...
  772.              */
  773.             case DM:
  774.                 SYNCHing = stilloob(net);
  775.                 settimer(gotDM);
  776.                 break;
  777.  
  778.  
  779.             /*
  780.              * Begin option subnegotiation...
  781.              */
  782.             case SB:
  783.                 state = TS_SB;
  784.                 continue;
  785.  
  786.             case WILL:
  787.                 state = TS_WILL;
  788.                 continue;
  789.  
  790.             case WONT:
  791.                 state = TS_WONT;
  792.                 continue;
  793.  
  794.             case DO:
  795.                 state = TS_DO;
  796.                 continue;
  797.  
  798.             case DONT:
  799.                 state = TS_DONT;
  800.                 continue;
  801.  
  802.             case IAC:
  803.                 *pfrontp++ = c;
  804.                 break;
  805.             }
  806.             state = TS_DATA;
  807.             break;
  808.  
  809.         case TS_SB:
  810.             if (c == IAC) {
  811.                 state = TS_SE;
  812.             } else {
  813.                 SB_ACCUM(c);
  814.             }
  815.             break;
  816.  
  817.         case TS_SE:
  818.             if (c != SE) {
  819.                 if (c != IAC) {
  820.                     SB_ACCUM(IAC);
  821.                 }
  822.                 SB_ACCUM(c);
  823.                 state = TS_SB;
  824.             } else {
  825.                 SB_TERM();
  826.                 suboption();    /* handle sub-option */
  827.                 state = TS_DATA;
  828.             }
  829.             break;
  830.  
  831.         case TS_WILL:
  832.             if (hisopts[c] != OPT_YES)
  833.                 willoption(c);
  834.             state = TS_DATA;
  835.             continue;
  836.  
  837.         case TS_WONT:
  838.             if (hisopts[c] != OPT_NO)
  839.                 wontoption(c);
  840.             state = TS_DATA;
  841.             continue;
  842.  
  843.         case TS_DO:
  844.             if (myopts[c] != OPT_YES)
  845.                 dooption(c);
  846.             state = TS_DATA;
  847.             continue;
  848.  
  849.         case TS_DONT:
  850.             if (myopts[c] != OPT_NO) {
  851.                 dontoption(c);
  852.             }
  853.             state = TS_DATA;
  854.             continue;
  855.  
  856.         default:
  857.             syslog(LOG_ERR, "telnetd: panic state=%d\n", state);
  858.             printf("telnetd: panic state=%d\n", state);
  859.             exit(1);
  860.         }
  861.     }
  862. }
  863.  
  864. willoption(option)
  865.     int option;
  866. {
  867.     char *fmt;
  868.  
  869.     switch (option) {
  870.  
  871.     case TELOPT_BINARY:
  872.         mode(RAW, 0);
  873.         fmt = doopt;
  874.         break;
  875.  
  876.     case TELOPT_ECHO:
  877.         not42 = 0;        /* looks like a 4.2 system */
  878.         /*
  879.          * Now, in a 4.2 system, to break them out of ECHOing
  880.          * (to the terminal) mode, we need to send a "WILL ECHO".
  881.          * Kludge upon kludge!
  882.          */
  883.         if (myopts[TELOPT_ECHO] == OPT_YES) {
  884.             dooption(TELOPT_ECHO);
  885.         }
  886.         fmt = dont;
  887.         break;
  888.  
  889.     case TELOPT_TTYPE:
  890.         settimer(ttypeopt);
  891.         if (hisopts[TELOPT_TTYPE] == OPT_YES_BUT_ALWAYS_LOOK) {
  892.             hisopts[TELOPT_TTYPE] = OPT_YES;
  893.             return;
  894.         }
  895.         fmt = doopt;
  896.         break;
  897.  
  898.     case TELOPT_SGA:
  899.         fmt = doopt;
  900.         break;
  901.  
  902.     case TELOPT_TM:
  903.         fmt = dont;
  904.         break;
  905.  
  906.     default:
  907.         fmt = dont;
  908.         break;
  909.     }
  910.     if (fmt == doopt) {
  911.         hisopts[option] = OPT_YES;
  912.     } else {
  913.         hisopts[option] = OPT_NO;
  914.     }
  915.     (void) sprintf(nfrontp, fmt, option);
  916.     nfrontp += sizeof (dont) - 2;
  917. }
  918.  
  919. wontoption(option)
  920.     int option;
  921. {
  922.     char *fmt;
  923.  
  924.     switch (option) {
  925.     case TELOPT_ECHO:
  926.         not42 = 1;        /* doesn't seem to be a 4.2 system */
  927.         break;
  928.  
  929.     case TELOPT_BINARY:
  930.         mode(0, RAW);
  931.         break;
  932.  
  933.     case TELOPT_TTYPE:
  934.         settimer(ttypeopt);
  935.         break;
  936.     }
  937.  
  938.     fmt = dont;
  939.     hisopts[option] = OPT_NO;
  940.     (void) sprintf(nfrontp, fmt, option);
  941.     nfrontp += sizeof (doopt) - 2;
  942. }
  943.  
  944. dooption(option)
  945.     int option;
  946. {
  947.     char *fmt;
  948.  
  949.     switch (option) {
  950.  
  951.     case TELOPT_TM:
  952.         fmt = wont;
  953.         break;
  954.  
  955.     case TELOPT_ECHO:
  956.         mode(ECHO|CRMOD, 0);
  957.         fmt = will;
  958.         break;
  959.  
  960.     case TELOPT_BINARY:
  961.         mode(RAW, 0);
  962.         fmt = will;
  963.         break;
  964.  
  965.     case TELOPT_SGA:
  966.         fmt = will;
  967.         break;
  968.  
  969.     default:
  970.         fmt = wont;
  971.         break;
  972.     }
  973.     if (fmt == will) {
  974.         myopts[option] = OPT_YES;
  975.     } else {
  976.         myopts[option] = OPT_NO;
  977.     }
  978.     (void) sprintf(nfrontp, fmt, option);
  979.     nfrontp += sizeof (doopt) - 2;
  980. }
  981.  
  982.  
  983. dontoption(option)
  984. int option;
  985. {
  986.     char *fmt;
  987.  
  988.     switch (option) {
  989.     case TELOPT_ECHO:        /* we should stop echoing */
  990.     mode(0, ECHO);
  991.     fmt = wont;
  992.     break;
  993.  
  994.     default:
  995.     fmt = wont;
  996.     break;
  997.     }
  998.  
  999.     if (fmt = wont) {
  1000.     myopts[option] = OPT_NO;
  1001.     } else {
  1002.     myopts[option] = OPT_YES;
  1003.     }
  1004.     (void) sprintf(nfrontp, fmt, option);
  1005.     nfrontp += sizeof (wont) - 2;
  1006. }
  1007.  
  1008. /*
  1009.  * suboption()
  1010.  *
  1011.  *    Look at the sub-option buffer, and try to be helpful to the other
  1012.  * side.
  1013.  *
  1014.  *    Currently we recognize:
  1015.  *
  1016.  *    Terminal type is
  1017.  */
  1018.  
  1019. suboption()
  1020. {
  1021.     switch (SB_GET()) {
  1022.     case TELOPT_TTYPE: {        /* Yaaaay! */
  1023.     static char terminalname[5+41] = "TERM=";
  1024.  
  1025.     settimer(ttypesubopt);
  1026.  
  1027.     if (SB_GET() != TELQUAL_IS) {
  1028.         return;        /* ??? XXX but, this is the most robust */
  1029.     }
  1030.  
  1031.     terminaltype = terminalname+strlen(terminalname);
  1032.  
  1033.     while ((terminaltype < (terminalname + sizeof terminalname-1)) &&
  1034.                                     !SB_EOF()) {
  1035.         register int c;
  1036.  
  1037.         c = SB_GET();
  1038.         if (isupper(c)) {
  1039.         c = tolower(c);
  1040.         }
  1041.         *terminaltype++ = c;    /* accumulate name */
  1042.     }
  1043.     *terminaltype = 0;
  1044.     terminaltype = terminalname;
  1045.     break;
  1046.     }
  1047.  
  1048.     default:
  1049.     ;
  1050.     }
  1051. }
  1052.  
  1053. mode(on, off)
  1054.     int on, off;
  1055. {
  1056.     struct sgttyb b;
  1057.  
  1058.     ptyflush();
  1059.     ioctl(pty, TIOCGETP, &b);
  1060.     b.sg_flags |= on;
  1061.     b.sg_flags &= ~off;
  1062.     ioctl(pty, TIOCSETP, &b);
  1063. }
  1064.  
  1065. /*
  1066.  * Send interrupt to process on other side of pty.
  1067.  * If it is in raw mode, just write NULL;
  1068.  * otherwise, write intr char.
  1069.  */
  1070. interrupt()
  1071. {
  1072.     struct sgttyb b;
  1073.     struct tchars tchars;
  1074.  
  1075.     ptyflush();    /* half-hearted */
  1076.     ioctl(pty, TIOCGETP, &b);
  1077.     if (b.sg_flags & RAW) {
  1078.         *pfrontp++ = '\0';
  1079.         return;
  1080.     }
  1081.     *pfrontp++ = ioctl(pty, TIOCGETC, &tchars) < 0 ?
  1082.         '\177' : tchars.t_intrc;
  1083. }
  1084.  
  1085. /*
  1086.  * Send quit to process on other side of pty.
  1087.  * If it is in raw mode, just write NULL;
  1088.  * otherwise, write quit char.
  1089.  */
  1090. sendbrk()
  1091. {
  1092.     struct sgttyb b;
  1093.     struct tchars tchars;
  1094.  
  1095.     ptyflush();    /* half-hearted */
  1096.     ioctl(pty, TIOCGETP, &b);
  1097.     if (b.sg_flags & RAW) {
  1098.         *pfrontp++ = '\0';
  1099.         return;
  1100.     }
  1101.     *pfrontp++ = ioctl(pty, TIOCGETC, &tchars) < 0 ?
  1102.         '\034' : tchars.t_quitc;
  1103. }
  1104.  
  1105. ptyflush()
  1106. {
  1107.     int n;
  1108.  
  1109.     if ((n = pfrontp - pbackp) > 0)
  1110.         n = write(pty, pbackp, n);
  1111.     if (n < 0)
  1112.         return;
  1113.     pbackp += n;
  1114.     if (pbackp == pfrontp)
  1115.         pbackp = pfrontp = ptyobuf;
  1116. }
  1117.  
  1118. /*
  1119.  * nextitem()
  1120.  *
  1121.  *    Return the address of the next "item" in the TELNET data
  1122.  * stream.  This will be the address of the next character if
  1123.  * the current address is a user data character, or it will
  1124.  * be the address of the character following the TELNET command
  1125.  * if the current address is a TELNET IAC ("I Am a Command")
  1126.  * character.
  1127.  */
  1128.  
  1129. char *
  1130. nextitem(current)
  1131. char    *current;
  1132. {
  1133.     if ((*current&0xff) != IAC) {
  1134.     return current+1;
  1135.     }
  1136.     switch (*(current+1)&0xff) {
  1137.     case DO:
  1138.     case DONT:
  1139.     case WILL:
  1140.     case WONT:
  1141.     return current+3;
  1142.     case SB:        /* loop forever looking for the SE */
  1143.     {
  1144.         register char *look = current+2;
  1145.  
  1146.         for (;;) {
  1147.         if ((*look++&0xff) == IAC) {
  1148.             if ((*look++&0xff) == SE) {
  1149.             return look;
  1150.             }
  1151.         }
  1152.         }
  1153.     }
  1154.     default:
  1155.     return current+2;
  1156.     }
  1157. }
  1158.  
  1159.  
  1160. /*
  1161.  * netclear()
  1162.  *
  1163.  *    We are about to do a TELNET SYNCH operation.  Clear
  1164.  * the path to the network.
  1165.  *
  1166.  *    Things are a bit tricky since we may have sent the first
  1167.  * byte or so of a previous TELNET command into the network.
  1168.  * So, we have to scan the network buffer from the beginning
  1169.  * until we are up to where we want to be.
  1170.  *
  1171.  *    A side effect of what we do, just to keep things
  1172.  * simple, is to clear the urgent data pointer.  The principal
  1173.  * caller should be setting the urgent data pointer AFTER calling
  1174.  * us in any case.
  1175.  */
  1176.  
  1177. netclear()
  1178. {
  1179.     register char *thisitem, *next;
  1180.     char *good;
  1181. #define    wewant(p)    ((nfrontp > p) && ((*p&0xff) == IAC) && \
  1182.                 ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
  1183.  
  1184.     thisitem = netobuf;
  1185.  
  1186.     while ((next = nextitem(thisitem)) <= nbackp) {
  1187.     thisitem = next;
  1188.     }
  1189.  
  1190.     /* Now, thisitem is first before/at boundary. */
  1191.  
  1192.     good = netobuf;    /* where the good bytes go */
  1193.  
  1194.     while (nfrontp > thisitem) {
  1195.     if (wewant(thisitem)) {
  1196.         int length;
  1197.  
  1198.         next = thisitem;
  1199.         do {
  1200.         next = nextitem(next);
  1201.         } while (wewant(next) && (nfrontp > next));
  1202.         length = next-thisitem;
  1203.         bcopy(thisitem, good, length);
  1204.         good += length;
  1205.         thisitem = next;
  1206.     } else {
  1207.         thisitem = nextitem(thisitem);
  1208.     }
  1209.     }
  1210.  
  1211.     nbackp = netobuf;
  1212.     nfrontp = good;        /* next byte to be sent */
  1213.     neturg = 0;
  1214. }
  1215.  
  1216. /*
  1217.  *  netflush
  1218.  *        Send as much data as possible to the network,
  1219.  *    handling requests for urgent data.
  1220.  */
  1221.  
  1222.  
  1223. netflush()
  1224. {
  1225.     int n;
  1226.  
  1227.     if ((n = nfrontp - nbackp) > 0) {
  1228.     /*
  1229.      * if no urgent data, or if the other side appears to be an
  1230.      * old 4.2 client (and thus unable to survive TCP urgent data),
  1231.      * write the entire buffer in non-OOB mode.
  1232.      */
  1233.     if ((neturg == 0) || (not42 == 0)) {
  1234.         n = write(net, nbackp, n);    /* normal write */
  1235.     } else {
  1236.         n = neturg - nbackp;
  1237.         /*
  1238.          * In 4.2 (and 4.3) systems, there is some question about
  1239.          * what byte in a sendOOB operation is the "OOB" data.
  1240.          * To make ourselves compatible, we only send ONE byte
  1241.          * out of band, the one WE THINK should be OOB (though
  1242.          * we really have more the TCP philosophy of urgent data
  1243.          * rather than the Unix philosophy of OOB data).
  1244.          */
  1245.         if (n > 1) {
  1246.         n = send(net, nbackp, n-1, 0);    /* send URGENT all by itself */
  1247.         } else {
  1248.         n = send(net, nbackp, n, MSG_OOB);    /* URGENT data */
  1249.         }
  1250.     }
  1251.     }
  1252.     if (n < 0) {
  1253.     if (errno == EWOULDBLOCK)
  1254.         return;
  1255.     /* should blow this guy away... */
  1256.     return;
  1257.     }
  1258.     nbackp += n;
  1259.     if (nbackp >= neturg) {
  1260.     neturg = 0;
  1261.     }
  1262.     if (nbackp == nfrontp) {
  1263.     nbackp = nfrontp = netobuf;
  1264.     }
  1265. }
  1266.  
  1267. cleanup()
  1268. {
  1269.     char *p;
  1270.  
  1271.     p = line + sizeof("/dev/") - 1;
  1272.     if (logout(p))
  1273.         logwtmp(p, "", "");
  1274.     (void)chmod(line, 0666);
  1275.     (void)chown(line, 0, 0);
  1276.     *p = 'p';
  1277.     (void)chmod(line, 0666);
  1278.     (void)chown(line, 0, 0);
  1279.     shutdown(net, 2);
  1280.     exit(1);
  1281. }
  1282.  
  1283. char    editedhost[32];
  1284.  
  1285. edithost(pat, host)
  1286.     register char *pat;
  1287.     register char *host;
  1288. {
  1289.     register char *res = editedhost;
  1290.  
  1291.     if (!pat)
  1292.         pat = "";
  1293.     while (*pat) {
  1294.         switch (*pat) {
  1295.  
  1296.         case '#':
  1297.             if (*host)
  1298.                 host++;
  1299.             break;
  1300.  
  1301.         case '@':
  1302.             if (*host)
  1303.                 *res++ = *host++;
  1304.             break;
  1305.  
  1306.         default:
  1307.             *res++ = *pat;
  1308.             break;
  1309.  
  1310.         }
  1311.         if (res == &editedhost[sizeof editedhost - 1]) {
  1312.             *res = '\0';
  1313.             return;
  1314.         }
  1315.         pat++;
  1316.     }
  1317.     if (*host)
  1318.         strncpy(res, host, sizeof editedhost - (res - editedhost) - 1);
  1319.     else
  1320.         *res = '\0';
  1321.     editedhost[sizeof editedhost - 1] = '\0';
  1322. }
  1323.  
  1324. static char *putlocation;
  1325.  
  1326. puts(s)
  1327. register char *s;
  1328. {
  1329.  
  1330.     while (*s)
  1331.         putchr(*s++);
  1332. }
  1333.  
  1334. putchr(cc)
  1335. {
  1336.     *putlocation++ = cc;
  1337. }
  1338.  
  1339. putf(cp, where)
  1340. register char *cp;
  1341. char *where;
  1342. {
  1343.     char *slash;
  1344.     char datebuffer[60];
  1345.     extern char *rindex();
  1346.  
  1347.     putlocation = where;
  1348.  
  1349.     while (*cp) {
  1350.         if (*cp != '%') {
  1351.             putchr(*cp++);
  1352.             continue;
  1353.         }
  1354.         switch (*++cp) {
  1355.  
  1356.         case 't':
  1357.             slash = rindex(line, '/');
  1358.             if (slash == (char *) 0)
  1359.                 puts(line);
  1360.             else
  1361.                 puts(&slash[1]);
  1362.             break;
  1363.  
  1364.         case 'h':
  1365.             puts(editedhost);
  1366.             break;
  1367.  
  1368.         case 'd':
  1369.             get_date(datebuffer);
  1370.             puts(datebuffer);
  1371.             break;
  1372.  
  1373.         case '%':
  1374.             putchr('%');
  1375.             break;
  1376.         }
  1377.         cp++;
  1378.     }
  1379. }
  1380.