home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / archival / ftp / BFTP.312 / bftpd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-06-29  |  27.0 KB  |  1,325 lines

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