home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / libexec / telnetd / utility.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-20  |  26.8 KB  |  1,172 lines

  1. /*
  2.  * Copyright (c) 1989 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. static char sccsid[] = "@(#)utility.c    5.8 (Berkeley) 3/22/91";
  36. #endif /* not lint */
  37.  
  38. #define PRINTOPTIONS
  39. #include "telnetd.h"
  40.  
  41. /*
  42.  * utility functions performing io related tasks
  43.  */
  44.  
  45. /*
  46.  * ttloop
  47.  *
  48.  *    A small subroutine to flush the network output buffer, get some data
  49.  * from the network, and pass it through the telnet state machine.  We
  50.  * also flush the pty input buffer (by dropping its data) if it becomes
  51.  * too full.
  52.  */
  53.  
  54.     void
  55. ttloop()
  56. {
  57.     void netflush();
  58.  
  59.     DIAG(TD_REPORT, {sprintf(nfrontp, "td: ttloop\r\n");
  60.              nfrontp += strlen(nfrontp);});
  61.     if (nfrontp-nbackp) {
  62.     netflush();
  63.     }
  64.     ncc = read(net, netibuf, sizeof netibuf);
  65.     if (ncc < 0) {
  66.     syslog(LOG_INFO, "ttloop:  read: %m\n");
  67.     exit(1);
  68.     } else if (ncc == 0) {
  69.     syslog(LOG_INFO, "ttloop:  peer died: %m\n");
  70.     exit(1);
  71.     }
  72.     DIAG(TD_REPORT, {sprintf(nfrontp, "td: ttloop read %d chars\r\n", ncc);
  73.              nfrontp += strlen(nfrontp);});
  74.     netip = netibuf;
  75.     telrcv();            /* state machine */
  76.     if (ncc > 0) {
  77.     pfrontp = pbackp = ptyobuf;
  78.     telrcv();
  79.     }
  80. }  /* end of ttloop */
  81.  
  82. /*
  83.  * Check a descriptor to see if out of band data exists on it.
  84.  */
  85.     int
  86. stilloob(s)
  87.     int    s;        /* socket number */
  88. {
  89.     static struct timeval timeout = { 0 };
  90.     fd_set    excepts;
  91.     int value;
  92.  
  93.     do {
  94.     FD_ZERO(&excepts);
  95.     FD_SET(s, &excepts);
  96.     value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);
  97.     } while ((value == -1) && (errno == EINTR));
  98.  
  99.     if (value < 0) {
  100.     fatalperror(pty, "select");
  101.     }
  102.     if (FD_ISSET(s, &excepts)) {
  103.     return 1;
  104.     } else {
  105.     return 0;
  106.     }
  107. }
  108.  
  109.     void
  110. ptyflush()
  111. {
  112.     int n;
  113.  
  114.     if ((n = pfrontp - pbackp) > 0) {
  115.         DIAG((TD_REPORT | TD_PTYDATA),
  116.             { sprintf(nfrontp, "td: ptyflush %d chars\r\n", n);
  117.               nfrontp += strlen(nfrontp); });
  118.         DIAG(TD_PTYDATA, printdata("pd", pbackp, n));
  119.         n = write(pty, pbackp, n);
  120.     }
  121.     if (n < 0) {
  122.         if (errno == EWOULDBLOCK || errno == EINTR)
  123.             return;
  124.         cleanup(0);
  125.     }
  126.     pbackp += n;
  127.     if (pbackp == pfrontp)
  128.         pbackp = pfrontp = ptyobuf;
  129. }
  130.  
  131. /*
  132.  * nextitem()
  133.  *
  134.  *    Return the address of the next "item" in the TELNET data
  135.  * stream.  This will be the address of the next character if
  136.  * the current address is a user data character, or it will
  137.  * be the address of the character following the TELNET command
  138.  * if the current address is a TELNET IAC ("I Am a Command")
  139.  * character.
  140.  */
  141.     char *
  142. nextitem(current)
  143.     char    *current;
  144. {
  145.     if ((*current&0xff) != IAC) {
  146.     return current+1;
  147.     }
  148.     switch (*(current+1)&0xff) {
  149.     case DO:
  150.     case DONT:
  151.     case WILL:
  152.     case WONT:
  153.     return current+3;
  154.     case SB:        /* loop forever looking for the SE */
  155.     {
  156.         register char *look = current+2;
  157.  
  158.         for (;;) {
  159.         if ((*look++&0xff) == IAC) {
  160.             if ((*look++&0xff) == SE) {
  161.             return look;
  162.             }
  163.         }
  164.         }
  165.     }
  166.     default:
  167.     return current+2;
  168.     }
  169. }  /* end of nextitem */
  170.  
  171.  
  172. /*
  173.  * netclear()
  174.  *
  175.  *    We are about to do a TELNET SYNCH operation.  Clear
  176.  * the path to the network.
  177.  *
  178.  *    Things are a bit tricky since we may have sent the first
  179.  * byte or so of a previous TELNET command into the network.
  180.  * So, we have to scan the network buffer from the beginning
  181.  * until we are up to where we want to be.
  182.  *
  183.  *    A side effect of what we do, just to keep things
  184.  * simple, is to clear the urgent data pointer.  The principal
  185.  * caller should be setting the urgent data pointer AFTER calling
  186.  * us in any case.
  187.  */
  188.     void
  189. netclear()
  190. {
  191.     register char *thisitem, *next;
  192.     char *good;
  193. #define    wewant(p)    ((nfrontp > p) && ((*p&0xff) == IAC) && \
  194.                 ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
  195.  
  196. #if    defined(ENCRYPT)
  197.     thisitem = nclearto > netobuf ? nclearto : netobuf;
  198. #else
  199.     thisitem = netobuf;
  200. #endif
  201.  
  202.     while ((next = nextitem(thisitem)) <= nbackp) {
  203.     thisitem = next;
  204.     }
  205.  
  206.     /* Now, thisitem is first before/at boundary. */
  207.  
  208. #if    defined(ENCRYPT)
  209.     good = nclearto > netobuf ? nclearto : netobuf;
  210. #else
  211.     good = netobuf;    /* where the good bytes go */
  212. #endif
  213.  
  214.     while (nfrontp > thisitem) {
  215.     if (wewant(thisitem)) {
  216.         int length;
  217.  
  218.         next = thisitem;
  219.         do {
  220.         next = nextitem(next);
  221.         } while (wewant(next) && (nfrontp > next));
  222.         length = next-thisitem;
  223.         bcopy(thisitem, good, length);
  224.         good += length;
  225.         thisitem = next;
  226.     } else {
  227.         thisitem = nextitem(thisitem);
  228.     }
  229.     }
  230.  
  231.     nbackp = netobuf;
  232.     nfrontp = good;        /* next byte to be sent */
  233.     neturg = 0;
  234. }  /* end of netclear */
  235.  
  236. /*
  237.  *  netflush
  238.  *        Send as much data as possible to the network,
  239.  *    handling requests for urgent data.
  240.  */
  241.     void
  242. netflush()
  243. {
  244.     int n;
  245.     extern int not42;
  246.  
  247.     if ((n = nfrontp - nbackp) > 0) {
  248.     DIAG(TD_REPORT,
  249.         { sprintf(nfrontp, "td: netflush %d chars\r\n", n);
  250.           n += strlen(nfrontp);  /* get count first */
  251.           nfrontp += strlen(nfrontp);  /* then move pointer */
  252.         });
  253. #if    defined(ENCRYPT)
  254.     if (encrypt_output) {
  255.         char *s = nclearto ? nclearto : nbackp;
  256.         if (nfrontp - s > 0) {
  257.             (*encrypt_output)((unsigned char *)s, nfrontp-s);
  258.             nclearto = nfrontp;
  259.         }
  260.     }
  261. #endif
  262.     /*
  263.      * if no urgent data, or if the other side appears to be an
  264.      * old 4.2 client (and thus unable to survive TCP urgent data),
  265.      * write the entire buffer in non-OOB mode.
  266.      */
  267.     if ((neturg == 0) || (not42 == 0)) {
  268.         n = write(net, nbackp, n);    /* normal write */
  269.     } else {
  270.         n = neturg - nbackp;
  271.         /*
  272.          * In 4.2 (and 4.3) systems, there is some question about
  273.          * what byte in a sendOOB operation is the "OOB" data.
  274.          * To make ourselves compatible, we only send ONE byte
  275.          * out of band, the one WE THINK should be OOB (though
  276.          * we really have more the TCP philosophy of urgent data
  277.          * rather than the Unix philosophy of OOB data).
  278.          */
  279.         if (n > 1) {
  280.         n = send(net, nbackp, n-1, 0);    /* send URGENT all by itself */
  281.         } else {
  282.         n = send(net, nbackp, n, MSG_OOB);    /* URGENT data */
  283.         }
  284.     }
  285.     }
  286.     if (n < 0) {
  287.     if (errno == EWOULDBLOCK || errno == EINTR)
  288.         return;
  289.     cleanup(0);
  290.     }
  291.     nbackp += n;
  292. #if    defined(ENCRYPT)
  293.     if (nbackp > nclearto)
  294.     nclearto = 0;
  295. #endif
  296.     if (nbackp >= neturg) {
  297.     neturg = 0;
  298.     }
  299.     if (nbackp == nfrontp) {
  300.     nbackp = nfrontp = netobuf;
  301. #if    defined(ENCRYPT)
  302.     nclearto = 0;
  303. #endif
  304.     }
  305.     return;
  306. }  /* end of netflush */
  307.  
  308.  
  309. /*
  310.  * writenet
  311.  *
  312.  * Just a handy little function to write a bit of raw data to the net.
  313.  * It will force a transmit of the buffer if necessary
  314.  *
  315.  * arguments
  316.  *    ptr - A pointer to a character string to write
  317.  *    len - How many bytes to write
  318.  */
  319.     void
  320. writenet(ptr, len)
  321.     register unsigned char *ptr;
  322.     register int len;
  323. {
  324.     /* flush buffer if no room for new data) */
  325.     if ((&netobuf[BUFSIZ] - nfrontp) < len) {
  326.         /* if this fails, don't worry, buffer is a little big */
  327.         netflush();
  328.     }
  329.  
  330.     bcopy(ptr, nfrontp, len);
  331.     nfrontp += len;
  332.  
  333. }  /* end of writenet */
  334.  
  335.  
  336. /*
  337.  * miscellaneous functions doing a variety of little jobs follow ...
  338.  */
  339.  
  340.  
  341.     void
  342. fatal(f, msg)
  343.     int f;
  344.     char *msg;
  345. {
  346.     char buf[BUFSIZ];
  347.  
  348.     (void) sprintf(buf, "telnetd: %s.\r\n", msg);
  349. #if    defined(ENCRYPT)
  350.     if (encrypt_output) {
  351.         /*
  352.          * Better turn off encryption first....
  353.          * Hope it flushes...
  354.          */
  355.         encrypt_send_end();
  356.         netflush();
  357.     }
  358. #endif
  359.     (void) write(f, buf, (int)strlen(buf));
  360.     sleep(1);    /*XXX*/
  361.     exit(1);
  362. }
  363.  
  364.     void
  365. fatalperror(f, msg)
  366.     int f;
  367.     char *msg;
  368. {
  369.     char buf[BUFSIZ], *strerror();
  370.  
  371.     (void) sprintf(buf, "%s: %s\r\n", msg, strerror(errno));
  372.     fatal(f, buf);
  373. }
  374.  
  375. char editedhost[32];
  376.  
  377.     void
  378. edithost(pat, host)
  379.     register char *pat;
  380.     register char *host;
  381. {
  382.     register char *res = editedhost;
  383.     char *strncpy();
  384.  
  385.     if (!pat)
  386.         pat = "";
  387.     while (*pat) {
  388.         switch (*pat) {
  389.  
  390.         case '#':
  391.             if (*host)
  392.                 host++;
  393.             break;
  394.  
  395.         case '@':
  396.             if (*host)
  397.                 *res++ = *host++;
  398.             break;
  399.  
  400.         default:
  401.             *res++ = *pat;
  402.             break;
  403.         }
  404.         if (res == &editedhost[sizeof editedhost - 1]) {
  405.             *res = '\0';
  406.             return;
  407.         }
  408.         pat++;
  409.     }
  410.     if (*host)
  411.         (void) strncpy(res, host,
  412.                 sizeof editedhost - (res - editedhost) -1);
  413.     else
  414.         *res = '\0';
  415.     editedhost[sizeof editedhost - 1] = '\0';
  416. }
  417.  
  418. static char *putlocation;
  419.  
  420.     void
  421. putstr(s)
  422.     register char *s;
  423. {
  424.  
  425.     while (*s)
  426.         putchr(*s++);
  427. }
  428.  
  429.     void
  430. putchr(cc)
  431.     int cc;
  432. {
  433.     *putlocation++ = cc;
  434. }
  435.  
  436. /*
  437.  * This is split on two lines so that SCCS will not see the M
  438.  * between two % signs and expand it...
  439.  */
  440. static char fmtstr[] = { "%l:%M\
  441. %P on %A, %d %B %Y" };
  442.  
  443.     void
  444. putf(cp, where)
  445.     register char *cp;
  446.     char *where;
  447. {
  448.     char *slash;
  449.     time_t t;
  450.     char db[100];
  451.     extern char *rindex();
  452.  
  453.     putlocation = where;
  454.  
  455.     while (*cp) {
  456.         if (*cp != '%') {
  457.             putchr(*cp++);
  458.             continue;
  459.         }
  460.         switch (*++cp) {
  461.  
  462.         case 't':
  463.             slash = rindex(line, '/');
  464.             if (slash == (char *) 0)
  465.                 putstr(line);
  466.             else
  467.                 putstr(&slash[1]);
  468.             break;
  469.  
  470.         case 'h':
  471.             putstr(editedhost);
  472.             break;
  473.  
  474.         case 'd':
  475.             (void)time(&t);
  476.             (void)strftime(db, sizeof(db), fmtstr, localtime(&t));
  477.             putstr(db);
  478.             break;
  479.  
  480.         case '%':
  481.             putchr('%');
  482.             break;
  483.         }
  484.         cp++;
  485.     }
  486. }
  487.  
  488. #ifdef DIAGNOSTICS
  489. /*
  490.  * Print telnet options and commands in plain text, if possible.
  491.  */
  492.     void
  493. printoption(fmt, option)
  494.     register char *fmt;
  495.     register int option;
  496. {
  497.     if (TELOPT_OK(option))
  498.         sprintf(nfrontp, "%s %s\r\n", fmt, TELOPT(option));
  499.     else if (TELCMD_OK(option))
  500.         sprintf(nfrontp, "%s %s\r\n", fmt, TELCMD(option));
  501.     else
  502.         sprintf(nfrontp, "%s %d\r\n", fmt, option);
  503.     nfrontp += strlen(nfrontp);
  504.     return;
  505. }
  506.  
  507.     void
  508. printsub(direction, pointer, length)
  509.     char        direction;    /* '<' or '>' */
  510.     unsigned char    *pointer;    /* where suboption data sits */
  511.     int            length;        /* length of suboption data */
  512. {
  513.     register int i;
  514.     char buf[512];
  515.  
  516.         if (!(diagnostic & TD_OPTIONS))
  517.         return;
  518.  
  519.     if (direction) {
  520.         sprintf(nfrontp, "td: %s suboption ",
  521.                     direction == '<' ? "recv" : "send");
  522.         nfrontp += strlen(nfrontp);
  523.         if (length >= 3) {
  524.         register int j;
  525.  
  526.         i = pointer[length-2];
  527.         j = pointer[length-1];
  528.  
  529.         if (i != IAC || j != SE) {
  530.             sprintf(nfrontp, "(terminated by ");
  531.             nfrontp += strlen(nfrontp);
  532.             if (TELOPT_OK(i))
  533.             sprintf(nfrontp, "%s ", TELOPT(i));
  534.             else if (TELCMD_OK(i))
  535.             sprintf(nfrontp, "%s ", TELCMD(i));
  536.             else
  537.             sprintf(nfrontp, "%d ", i);
  538.             nfrontp += strlen(nfrontp);
  539.             if (TELOPT_OK(j))
  540.             sprintf(nfrontp, "%s", TELOPT(j));
  541.             else if (TELCMD_OK(j))
  542.             sprintf(nfrontp, "%s", TELCMD(j));
  543.             else
  544.             sprintf(nfrontp, "%d", j);
  545.             nfrontp += strlen(nfrontp);
  546.             sprintf(nfrontp, ", not IAC SE!) ");
  547.             nfrontp += strlen(nfrontp);
  548.         }
  549.         }
  550.         length -= 2;
  551.     }
  552.     if (length < 1) {
  553.         sprintf(nfrontp, "(Empty suboption???)");
  554.         nfrontp += strlen(nfrontp);
  555.         return;
  556.     }
  557.     switch (pointer[0]) {
  558.     case TELOPT_TTYPE:
  559.         sprintf(nfrontp, "TERMINAL-TYPE ");
  560.         nfrontp += strlen(nfrontp);
  561.         switch (pointer[1]) {
  562.         case TELQUAL_IS:
  563.         sprintf(nfrontp, "IS \"%.*s\"", length-2, (char *)pointer+2);
  564.         break;
  565.         case TELQUAL_SEND:
  566.         sprintf(nfrontp, "SEND");
  567.         break;
  568.         default:
  569.         sprintf(nfrontp,
  570.                 "- unknown qualifier %d (0x%x).",
  571.                 pointer[1], pointer[1]);
  572.         }
  573.         nfrontp += strlen(nfrontp);
  574.         break;
  575.     case TELOPT_TSPEED:
  576.         sprintf(nfrontp, "TERMINAL-SPEED");
  577.         nfrontp += strlen(nfrontp);
  578.         if (length < 2) {
  579.         sprintf(nfrontp, " (empty suboption???)");
  580.         nfrontp += strlen(nfrontp);
  581.         break;
  582.         }
  583.         switch (pointer[1]) {
  584.         case TELQUAL_IS:
  585.         sprintf(nfrontp, " IS %.*s", length-2, (char *)pointer+2);
  586.         nfrontp += strlen(nfrontp);
  587.         break;
  588.         default:
  589.         if (pointer[1] == 1)
  590.             sprintf(nfrontp, " SEND");
  591.         else
  592.             sprintf(nfrontp, " %d (unknown)", pointer[1]);
  593.         nfrontp += strlen(nfrontp);
  594.         for (i = 2; i < length; i++) {
  595.             sprintf(nfrontp, " ?%d?", pointer[i]);
  596.             nfrontp += strlen(nfrontp);
  597.         }
  598.         break;
  599.         }
  600.         break;
  601.  
  602.     case TELOPT_LFLOW:
  603.         sprintf(nfrontp, "TOGGLE-FLOW-CONTROL");
  604.         nfrontp += strlen(nfrontp);
  605.         if (length < 2) {
  606.         sprintf(nfrontp, " (empty suboption???)");
  607.         nfrontp += strlen(nfrontp);
  608.         break;
  609.         }
  610.         switch (pointer[1]) {
  611.         case 0:
  612.         sprintf(nfrontp, " OFF"); break;
  613.         case 1:
  614.         sprintf(nfrontp, " ON"); break;
  615.         default:
  616.         sprintf(nfrontp, " %d (unknown)", pointer[1]);
  617.         }
  618.         nfrontp += strlen(nfrontp);
  619.         for (i = 2; i < length; i++) {
  620.         sprintf(nfrontp, " ?%d?", pointer[i]);
  621.         nfrontp += strlen(nfrontp);
  622.         }
  623.         break;
  624.  
  625.     case TELOPT_NAWS:
  626.         sprintf(nfrontp, "NAWS");
  627.         nfrontp += strlen(nfrontp);
  628.         if (length < 2) {
  629.         sprintf(nfrontp, " (empty suboption???)");
  630.         nfrontp += strlen(nfrontp);
  631.         break;
  632.         }
  633.         if (length == 2) {
  634.         sprintf(nfrontp, " ?%d?", pointer[1]);
  635.         nfrontp += strlen(nfrontp);
  636.         break;
  637.         }
  638.         sprintf(nfrontp, " %d %d (%d)",
  639.         pointer[1], pointer[2],
  640.         (int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2])));
  641.         nfrontp += strlen(nfrontp);
  642.         if (length == 4) {
  643.         sprintf(nfrontp, " ?%d?", pointer[3]);
  644.         nfrontp += strlen(nfrontp);
  645.         break;
  646.         }
  647.         sprintf(nfrontp, " %d %d (%d)",
  648.         pointer[3], pointer[4],
  649.         (int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4])));
  650.         nfrontp += strlen(nfrontp);
  651.         for (i = 5; i < length; i++) {
  652.         sprintf(nfrontp, " ?%d?", pointer[i]);
  653.         nfrontp += strlen(nfrontp);
  654.         }
  655.         break;
  656.  
  657.     case TELOPT_LINEMODE:
  658.         sprintf(nfrontp, "LINEMODE ");
  659.         nfrontp += strlen(nfrontp);
  660.         if (length < 2) {
  661.         sprintf(nfrontp, " (empty suboption???)");
  662.         nfrontp += strlen(nfrontp);
  663.         break;
  664.         }
  665.         switch (pointer[1]) {
  666.         case WILL:
  667.         sprintf(nfrontp, "WILL ");
  668.         goto common;
  669.         case WONT:
  670.         sprintf(nfrontp, "WONT ");
  671.         goto common;
  672.         case DO:
  673.         sprintf(nfrontp, "DO ");
  674.         goto common;
  675.         case DONT:
  676.         sprintf(nfrontp, "DONT ");
  677.         common:
  678.         nfrontp += strlen(nfrontp);
  679.         if (length < 3) {
  680.             sprintf(nfrontp, "(no option???)");
  681.             nfrontp += strlen(nfrontp);
  682.             break;
  683.         }
  684.         switch (pointer[2]) {
  685.         case LM_FORWARDMASK:
  686.             sprintf(nfrontp, "Forward Mask");
  687.             nfrontp += strlen(nfrontp);
  688.             for (i = 3; i < length; i++) {
  689.             sprintf(nfrontp, " %x", pointer[i]);
  690.             nfrontp += strlen(nfrontp);
  691.             }
  692.             break;
  693.         default:
  694.             sprintf(nfrontp, "%d (unknown)", pointer[2]);
  695.             nfrontp += strlen(nfrontp);
  696.             for (i = 3; i < length; i++) {
  697.             sprintf(nfrontp, " %d", pointer[i]);
  698.             nfrontp += strlen(nfrontp);
  699.             }
  700.             break;
  701.         }
  702.         break;
  703.         
  704.         case LM_SLC:
  705.         sprintf(nfrontp, "SLC");
  706.         nfrontp += strlen(nfrontp);
  707.         for (i = 2; i < length - 2; i += 3) {
  708.             if (SLC_NAME_OK(pointer[i+SLC_FUNC]))
  709.             sprintf(nfrontp, " %s", SLC_NAME(pointer[i+SLC_FUNC]));
  710.             else
  711.             sprintf(nfrontp, " %d", pointer[i+SLC_FUNC]);
  712.             nfrontp += strlen(nfrontp);
  713.             switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) {
  714.             case SLC_NOSUPPORT:
  715.             sprintf(nfrontp, " NOSUPPORT"); break;
  716.             case SLC_CANTCHANGE:
  717.             sprintf(nfrontp, " CANTCHANGE"); break;
  718.             case SLC_VARIABLE:
  719.             sprintf(nfrontp, " VARIABLE"); break;
  720.             case SLC_DEFAULT:
  721.             sprintf(nfrontp, " DEFAULT"); break;
  722.             }
  723.             nfrontp += strlen(nfrontp);
  724.             sprintf(nfrontp, "%s%s%s",
  725.             pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "",
  726.             pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "",
  727.             pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : "");
  728.             nfrontp += strlen(nfrontp);
  729.             if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN|
  730.                         SLC_FLUSHOUT| SLC_LEVELBITS)) {
  731.             sprintf(nfrontp, "(0x%x)", pointer[i+SLC_FLAGS]);
  732.             nfrontp += strlen(nfrontp);
  733.             }
  734.             sprintf(nfrontp, " %d;", pointer[i+SLC_VALUE]);
  735.             nfrontp += strlen(nfrontp);
  736.             if ((pointer[i+SLC_VALUE] == IAC) &&
  737.             (pointer[i+SLC_VALUE+1] == IAC))
  738.                 i++;
  739.         }
  740.         for (; i < length; i++) {
  741.             sprintf(nfrontp, " ?%d?", pointer[i]);
  742.             nfrontp += strlen(nfrontp);
  743.         }
  744.         break;
  745.  
  746.         case LM_MODE:
  747.         sprintf(nfrontp, "MODE ");
  748.         nfrontp += strlen(nfrontp);
  749.         if (length < 3) {
  750.             sprintf(nfrontp, "(no mode???)");
  751.             nfrontp += strlen(nfrontp);
  752.             break;
  753.         }
  754.         {
  755.             char tbuf[32];
  756.             sprintf(tbuf, "%s%s%s%s%s",
  757.             pointer[2]&MODE_EDIT ? "|EDIT" : "",
  758.             pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "",
  759.             pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "",
  760.             pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "",
  761.             pointer[2]&MODE_ACK ? "|ACK" : "");
  762.             sprintf(nfrontp, "%s", tbuf[1] ? &tbuf[1] : "0");
  763.             nfrontp += strlen(nfrontp);
  764.         }
  765.         if (pointer[2]&~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK)) {
  766.             sprintf(nfrontp, " (0x%x)", pointer[2]);
  767.             nfrontp += strlen(nfrontp);
  768.         }
  769.         for (i = 3; i < length; i++) {
  770.             sprintf(nfrontp, " ?0x%x?", pointer[i]);
  771.             nfrontp += strlen(nfrontp);
  772.         }
  773.         break;
  774.         default:
  775.         sprintf(nfrontp, "%d (unknown)", pointer[1]);
  776.         nfrontp += strlen(nfrontp);
  777.         for (i = 2; i < length; i++) {
  778.             sprintf(nfrontp, " %d", pointer[i]);
  779.             nfrontp += strlen(nfrontp);
  780.         }
  781.         }
  782.         break;
  783.  
  784.     case TELOPT_STATUS: {
  785.         register char *cp;
  786.         register int j, k;
  787.  
  788.         sprintf(nfrontp, "STATUS");
  789.         nfrontp += strlen(nfrontp);
  790.  
  791.         switch (pointer[1]) {
  792.         default:
  793.         if (pointer[1] == TELQUAL_SEND)
  794.             sprintf(nfrontp, " SEND");
  795.         else
  796.             sprintf(nfrontp, " %d (unknown)", pointer[1]);
  797.         nfrontp += strlen(nfrontp);
  798.         for (i = 2; i < length; i++) {
  799.             sprintf(nfrontp, " ?%d?", pointer[i]);
  800.             nfrontp += strlen(nfrontp);
  801.         }
  802.         break;
  803.         case TELQUAL_IS:
  804.         sprintf(nfrontp, " IS\r\n");
  805.         nfrontp += strlen(nfrontp);
  806.  
  807.         for (i = 2; i < length; i++) {
  808.             switch(pointer[i]) {
  809.             case DO:    cp = "DO"; goto common2;
  810.             case DONT:    cp = "DONT"; goto common2;
  811.             case WILL:    cp = "WILL"; goto common2;
  812.             case WONT:    cp = "WONT"; goto common2;
  813.             common2:
  814.             i++;
  815.             if (TELOPT_OK((int)pointer[i]))
  816.                 sprintf(nfrontp, " %s %s", cp, TELOPT(pointer[i]));
  817.             else
  818.                 sprintf(nfrontp, " %s %d", cp, pointer[i]);
  819.             nfrontp += strlen(nfrontp);
  820.  
  821.             sprintf(nfrontp, "\r\n");
  822.             nfrontp += strlen(nfrontp);
  823.             break;
  824.  
  825.             case SB:
  826.             sprintf(nfrontp, " SB ");
  827.             nfrontp += strlen(nfrontp);
  828.             i++;
  829.             j = k = i;
  830.             while (j < length) {
  831.                 if (pointer[j] == SE) {
  832.                 if (j+1 == length)
  833.                     break;
  834.                 if (pointer[j+1] == SE)
  835.                     j++;
  836.                 else
  837.                     break;
  838.                 }
  839.                 pointer[k++] = pointer[j++];
  840.             }
  841.             printsub(0, &pointer[i], k - i);
  842.             if (i < length) {
  843.                 sprintf(nfrontp, " SE");
  844.                 nfrontp += strlen(nfrontp);
  845.                 i = j;
  846.             } else
  847.                 i = j - 1;
  848.  
  849.             sprintf(nfrontp, "\r\n");
  850.             nfrontp += strlen(nfrontp);
  851.  
  852.             break;
  853.                 
  854.             default:
  855.             sprintf(nfrontp, " %d", pointer[i]);
  856.             nfrontp += strlen(nfrontp);
  857.             break;
  858.             }
  859.         }
  860.         break;
  861.         }
  862.         break;
  863.       }
  864.  
  865.     case TELOPT_XDISPLOC:
  866.         sprintf(nfrontp, "X-DISPLAY-LOCATION ");
  867.         nfrontp += strlen(nfrontp);
  868.         switch (pointer[1]) {
  869.         case TELQUAL_IS:
  870.         sprintf(nfrontp, "IS \"%.*s\"", length-2, (char *)pointer+2);
  871.         break;
  872.         case TELQUAL_SEND:
  873.         sprintf(nfrontp, "SEND");
  874.         break;
  875.         default:
  876.         sprintf(nfrontp, "- unknown qualifier %d (0x%x).",
  877.                 pointer[1], pointer[1]);
  878.         }
  879.         nfrontp += strlen(nfrontp);
  880.         break;
  881.  
  882.     case TELOPT_ENVIRON:
  883.         sprintf(nfrontp, "ENVIRON ");
  884.         nfrontp += strlen(nfrontp);
  885.         switch (pointer[1]) {
  886.         case TELQUAL_IS:
  887.         sprintf(nfrontp, "IS ");
  888.         goto env_common;
  889.         case TELQUAL_SEND:
  890.         sprintf(nfrontp, "SEND ");
  891.         goto env_common;
  892.         case TELQUAL_INFO:
  893.         sprintf(nfrontp, "INFO ");
  894.         env_common:
  895.         nfrontp += strlen(nfrontp);
  896.         {
  897.             register int noquote = 2;
  898.             for (i = 2; i < length; i++ ) {
  899.             switch (pointer[i]) {
  900.             case ENV_VAR:
  901.                 if (pointer[1] == TELQUAL_SEND)
  902.                 goto def_case;
  903.                 sprintf(nfrontp, "\" VAR " + noquote);
  904.                 nfrontp += strlen(nfrontp);
  905.                 noquote = 2;
  906.                 break;
  907.  
  908.             case ENV_VALUE:
  909.                 sprintf(nfrontp, "\" VALUE " + noquote);
  910.                 nfrontp += strlen(nfrontp);
  911.                 noquote = 2;
  912.                 break;
  913.  
  914.             case ENV_ESC:
  915.                 sprintf(nfrontp, "\" ESC " + noquote);
  916.                 nfrontp += strlen(nfrontp);
  917.                 noquote = 2;
  918.                 break;
  919.  
  920.             default:
  921.             def_case:
  922.                 if (isprint(pointer[i]) && pointer[i] != '"') {
  923.                 if (noquote) {
  924.                     *nfrontp++ = '"';
  925.                     noquote = 0;
  926.                 }
  927.                 *nfrontp++ = pointer[i];
  928.                 } else {
  929.                 sprintf(nfrontp, "\" %03o " + noquote,
  930.                             pointer[i]);
  931.                 nfrontp += strlen(nfrontp);
  932.                 noquote = 2;
  933.                 }
  934.                 break;
  935.             }
  936.             }
  937.             if (!noquote)
  938.             *nfrontp++ = '"';
  939.             break;
  940.         }
  941.         }
  942.         break;
  943.  
  944. #if    defined(AUTHENTICATE)
  945.     case TELOPT_AUTHENTICATION:
  946.         sprintf(nfrontp, "AUTHENTICATION");
  947.         nfrontp += strlen(nfrontp);
  948.     
  949.         if (length < 2) {
  950.         sprintf(nfrontp, " (empty suboption???)");
  951.         nfrontp += strlen(nfrontp);
  952.         break;
  953.         }
  954.         switch (pointer[1]) {
  955.         case TELQUAL_REPLY:
  956.         case TELQUAL_IS:
  957.         sprintf(nfrontp, " %s ", (pointer[1] == TELQUAL_IS) ?
  958.                             "IS" : "REPLY");
  959.         nfrontp += strlen(nfrontp);
  960.         if (AUTHTYPE_NAME_OK(pointer[2]))
  961.             sprintf(nfrontp, "%s ", AUTHTYPE_NAME(pointer[2]));
  962.         else
  963.             sprintf(nfrontp, "%d ", pointer[2]);
  964.         nfrontp += strlen(nfrontp);
  965.         if (length < 3) {
  966.             sprintf(nfrontp, "(partial suboption???)");
  967.             nfrontp += strlen(nfrontp);
  968.             break;
  969.         }
  970.         sprintf(nfrontp, "%s|%s",
  971.             ((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
  972.             "CLIENT" : "SERVER",
  973.             ((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
  974.             "MUTUAL" : "ONE-WAY");
  975.         nfrontp += strlen(nfrontp);
  976.  
  977.         auth_printsub(&pointer[1], length - 1, buf, sizeof(buf));
  978.         sprintf(nfrontp, "%s", buf);
  979.         nfrontp += strlen(nfrontp);
  980.         break;
  981.  
  982.         case TELQUAL_SEND:
  983.         i = 2;
  984.         sprintf(nfrontp, " SEND ");
  985.         nfrontp += strlen(nfrontp);
  986.         while (i < length) {
  987.             if (AUTHTYPE_NAME_OK(pointer[i]))
  988.             sprintf(nfrontp, "%s ", AUTHTYPE_NAME(pointer[i]));
  989.             else
  990.             sprintf(nfrontp, "%d ", pointer[i]);
  991.             nfrontp += strlen(nfrontp);
  992.             if (++i >= length) {
  993.             sprintf(nfrontp, "(partial suboption???)");
  994.             nfrontp += strlen(nfrontp);
  995.             break;
  996.             }
  997.             sprintf(nfrontp, "%s|%s ",
  998.             ((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
  999.                             "CLIENT" : "SERVER",
  1000.             ((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
  1001.                             "MUTUAL" : "ONE-WAY");
  1002.             nfrontp += strlen(nfrontp);
  1003.             ++i;
  1004.         }
  1005.         break;
  1006.  
  1007.         case TELQUAL_NAME:
  1008.         i = 2;
  1009.         sprintf(nfrontp, " NAME \"");
  1010.         nfrontp += strlen(nfrontp);
  1011.         while (i < length)
  1012.             *nfrontp += pointer[i++];
  1013.         *nfrontp += '"';
  1014.         break;
  1015.  
  1016.         default:
  1017.             for (i = 2; i < length; i++) {
  1018.             sprintf(nfrontp, " ?%d?", pointer[i]);
  1019.             nfrontp += strlen(nfrontp);
  1020.             }
  1021.             break;
  1022.         }
  1023.         break;
  1024. #endif
  1025.  
  1026. #if    defined(ENCRYPT)
  1027.     case TELOPT_ENCRYPT:
  1028.         sprintf(nfrontp, "ENCRYPT");
  1029.         nfrontp += strlen(nfrontp);
  1030.         if (length < 2) {
  1031.         sprintf(nfrontp, " (empty suboption???)");
  1032.         nfrontp += strlen(nfrontp);
  1033.         break;
  1034.         }
  1035.         switch (pointer[1]) {
  1036.         case ENCRYPT_START:
  1037.         sprintf(nfrontp, " START");
  1038.         nfrontp += strlen(nfrontp);
  1039.         break;
  1040.  
  1041.         case ENCRYPT_END:
  1042.         sprintf(nfrontp, " END");
  1043.         nfrontp += strlen(nfrontp);
  1044.         break;
  1045.  
  1046.         case ENCRYPT_REQSTART:
  1047.         sprintf(nfrontp, " REQUEST-START");
  1048.         nfrontp += strlen(nfrontp);
  1049.         break;
  1050.  
  1051.         case ENCRYPT_REQEND:
  1052.         sprintf(nfrontp, " REQUEST-END");
  1053.         nfrontp += strlen(nfrontp);
  1054.         break;
  1055.  
  1056.         case ENCRYPT_IS:
  1057.         case ENCRYPT_REPLY:
  1058.         sprintf(nfrontp, " %s ", (pointer[1] == ENCRYPT_IS) ?
  1059.                             "IS" : "REPLY");
  1060.         nfrontp += strlen(nfrontp);
  1061.         if (length < 3) {
  1062.             sprintf(nfrontp, " (partial suboption???)");
  1063.             nfrontp += strlen(nfrontp);
  1064.             break;
  1065.         }
  1066.         if (ENCTYPE_NAME_OK(pointer[2]))
  1067.             sprintf(nfrontp, "%s ", ENCTYPE_NAME(pointer[2]));
  1068.         else
  1069.             sprintf(nfrontp, " %d (unknown)", pointer[2]);
  1070.         nfrontp += strlen(nfrontp);
  1071.  
  1072.         encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf));
  1073.         sprintf(nfrontp, "%s", buf);
  1074.         nfrontp += strlen(nfrontp);
  1075.         break;
  1076.  
  1077.         case ENCRYPT_SUPPORT:
  1078.         i = 2;
  1079.         sprintf(nfrontp, " SUPPORT ");
  1080.         nfrontp += strlen(nfrontp);
  1081.         while (i < length) {
  1082.             if (ENCTYPE_NAME_OK(pointer[i]))
  1083.             sprintf(nfrontp, "%s ", ENCTYPE_NAME(pointer[i]));
  1084.             else
  1085.             sprintf(nfrontp, "%d ", pointer[i]);
  1086.             nfrontp += strlen(nfrontp);
  1087.             i++;
  1088.         }
  1089.         break;
  1090.  
  1091.         case ENCRYPT_ENC_KEYID:
  1092.         sprintf(nfrontp, " ENC_KEYID", pointer[1]);
  1093.         nfrontp += strlen(nfrontp);
  1094.         goto encommon;
  1095.  
  1096.         case ENCRYPT_DEC_KEYID:
  1097.         sprintf(nfrontp, " DEC_KEYID", pointer[1]);
  1098.         nfrontp += strlen(nfrontp);
  1099.         goto encommon;
  1100.  
  1101.         default:
  1102.         sprintf(nfrontp, " %d (unknown)", pointer[1]);
  1103.         nfrontp += strlen(nfrontp);
  1104.         encommon:
  1105.         for (i = 2; i < length; i++) {
  1106.             sprintf(nfrontp, " %d", pointer[i]);
  1107.             nfrontp += strlen(nfrontp);
  1108.         }
  1109.         break;
  1110.         }
  1111.         break;
  1112. #endif
  1113.  
  1114.     default:
  1115.         if (TELOPT_OK(pointer[0]))
  1116.             sprintf(nfrontp, "%s (unknown)", TELOPT(pointer[0]));
  1117.         else
  1118.             sprintf(nfrontp, "%d (unknown)", pointer[i]);
  1119.         nfrontp += strlen(nfrontp);
  1120.         for (i = 1; i < length; i++) {
  1121.         sprintf(nfrontp, " %d", pointer[i]);
  1122.         nfrontp += strlen(nfrontp);
  1123.         }
  1124.         break;
  1125.     }
  1126.     sprintf(nfrontp, "\r\n");
  1127.     nfrontp += strlen(nfrontp);
  1128. }
  1129.  
  1130. /*
  1131.  * Dump a data buffer in hex and ascii to the output data stream.
  1132.  */
  1133.     void
  1134. printdata(tag, ptr, cnt)
  1135.     register char *tag;
  1136.     register char *ptr;
  1137.     register int cnt;
  1138. {
  1139.     register int i;
  1140.     char xbuf[30];
  1141.  
  1142.     while (cnt) {
  1143.         /* flush net output buffer if no room for new data) */
  1144.         if ((&netobuf[BUFSIZ] - nfrontp) < 80) {
  1145.             netflush();
  1146.         }
  1147.  
  1148.         /* add a line of output */
  1149.         sprintf(nfrontp, "%s: ", tag);
  1150.         nfrontp += strlen(nfrontp);
  1151.         for (i = 0; i < 20 && cnt; i++) {
  1152.             sprintf(nfrontp, "%02x", *ptr);
  1153.             nfrontp += strlen(nfrontp); 
  1154.             if (isprint(*ptr)) {
  1155.                 xbuf[i] = *ptr;
  1156.             } else {
  1157.                 xbuf[i] = '.';
  1158.             }
  1159.             if (i % 2) { 
  1160.                 *nfrontp = ' ';
  1161.                 nfrontp++;
  1162.             }
  1163.             cnt--;
  1164.             ptr++;
  1165.         }
  1166.         xbuf[i] = '\0';
  1167.         sprintf(nfrontp, " %s\r\n", xbuf );
  1168.         nfrontp += strlen(nfrontp);
  1169.     } 
  1170. }
  1171. #endif /* DIAGNOSTICS */
  1172.